rff 0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/audio_handler.rb +184 -0
- data/lib/exceptions.rb +31 -0
- data/lib/output_reader.rb +61 -0
- data/lib/processor.rb +626 -0
- data/lib/rff.rb +5 -0
- data/lib/video_handler.rb +187 -0
- metadata +52 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 246923c57cdd775302fc981bf79ed642effccf5f
|
4
|
+
data.tar.gz: a77efae571f4648bee009534e10f608d094d65a9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3ffbd9f2fb140174e8c2e927b7fa4d5dd4ee4bf1529bbb51573be045d22ea2a95fef8e8b966e70c9b4ca2ab9f793ccabaff172cc1fadc026033498094f9d000d
|
7
|
+
data.tar.gz: 967e748b929e7c7121fa020b48065cf70426ed4944cbb5abd39eafee810ff18e4df3ad9ca59e4a728fc661d0a39d6256189df7a93e057b3e59b462ef19fccd2f
|
@@ -0,0 +1,184 @@
|
|
1
|
+
require_relative 'processor'
|
2
|
+
|
3
|
+
# The main module for _rff_ - a Ruby gem for simple audio and video conversion for HTML5 using FFmpeg
|
4
|
+
# Author:: Phitherek_ <phitherek [at] gmail [dot] com>
|
5
|
+
# License:: Open Source Software
|
6
|
+
|
7
|
+
module RFF
|
8
|
+
|
9
|
+
# This class provides an "All audio to HTML5" conversion functionality. It takes every compatible with FFmpeg audio format and converts it to the three HTML5 audio formats - mp3, ogg and wav. If the input is already in one of these formats it is only converted to the two other formats, because it can be used as one of HTML5 sources.
|
10
|
+
|
11
|
+
class AudioHandler
|
12
|
+
|
13
|
+
# This constructor initializes the class with the following arguments:
|
14
|
+
# * _input_ <b>(required)</b> - the full path to the input file
|
15
|
+
# * <i>output_path</i> - a path to place the output file in. Defaults to nil, which means that the input' s directory path is used
|
16
|
+
# * <i>custom_args</i> - passes custom arguments to FFmpeg. Defaults to nil, which means no custom arguments are given
|
17
|
+
# * <i>recommended_audio_quality</i> - determines if recommended by FFmpeg community audio quality settings should be used. Defaults to true, which means audio conversion with good, recommended quality. Set to false if you are giving additional arguments that determine this quality.
|
18
|
+
# All of the arguments are passed on to underlying Processor instances. This method also determines input type, initializes processing percentage and creates needed Processor instances.
|
19
|
+
|
20
|
+
def initialize input, output_path=nil, custom_args=nil, recommended_audio_quality=true
|
21
|
+
@input = input
|
22
|
+
@input_type = File.basename(@input).split(".")[1]
|
23
|
+
@output_path = output_path
|
24
|
+
@custom_args = custom_args
|
25
|
+
@processing_percentage = 0
|
26
|
+
@processors = []
|
27
|
+
types = [:mp3, :ogg, :wav]
|
28
|
+
if types.include?(@input_type.to_sym)
|
29
|
+
types.delete(@input_type.to_sym)
|
30
|
+
end
|
31
|
+
types.each do |type|
|
32
|
+
@processors << RFF::Processor.new(@input, type, @output_path, nil, @custom_args, recommended_audio_quality)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# This method fires all the Processor instances (conversion processes) in a separate thread at once. Then it counts the overall processing percentage from all the Processor instances as the process goes and sets it to 100% on finish
|
37
|
+
|
38
|
+
def fire_all
|
39
|
+
@processing_thread = Thread.new do |th|
|
40
|
+
begin
|
41
|
+
@processors.each do |proc|
|
42
|
+
proc.fire
|
43
|
+
#sleep(5)
|
44
|
+
end
|
45
|
+
status = :processing
|
46
|
+
while status != :done
|
47
|
+
donecount = 0
|
48
|
+
@processors.each do |proc|
|
49
|
+
#puts "Process status:" + proc.status.to_s
|
50
|
+
if proc.status == :completed || proc.status == :failed || proc.status == :aborted
|
51
|
+
donecount = donecount + 1
|
52
|
+
end
|
53
|
+
end
|
54
|
+
#puts "Done count: " + donecount.to_s
|
55
|
+
if donecount == @processors.count
|
56
|
+
status = :done
|
57
|
+
break
|
58
|
+
end
|
59
|
+
processing_percentage = 0
|
60
|
+
@processors.each do |proc|
|
61
|
+
processing_percentage += proc.processing_percentage
|
62
|
+
end
|
63
|
+
@processing_percentage = (processing_percentage.to_f/@processors.count).to_i
|
64
|
+
end
|
65
|
+
@processing_percentage = 100
|
66
|
+
rescue => e
|
67
|
+
puts "Caught exception: " + e.to_s
|
68
|
+
puts "Backtrace:"
|
69
|
+
puts e.backtrace
|
70
|
+
@status = :done
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
# This method fires all the Processor instances (conversion processes) in a separate thread sequentially - next Processor in the row is fired only after the Processor before finishes. It also counts the overall processing percentage from all the Processor instances as the process goes and sets it to 100% on finish
|
77
|
+
|
78
|
+
def fire_sequential
|
79
|
+
@processing_thread = Thread.new do |th|
|
80
|
+
begin
|
81
|
+
i = 0
|
82
|
+
@processors.each do |proc|
|
83
|
+
proc.fire
|
84
|
+
sleep(1)
|
85
|
+
while proc.status == :processing
|
86
|
+
if proc.processing_percentage != nil
|
87
|
+
@processing_percentage = (i*(100/@processors.count))+(proc.processing_percentage.to_f/@processors.count).to_i
|
88
|
+
end
|
89
|
+
end
|
90
|
+
i = i+1
|
91
|
+
#sleep(5)
|
92
|
+
end
|
93
|
+
@processing_percentage = 100
|
94
|
+
rescue => e
|
95
|
+
puts "Caught exception: " + e.to_s
|
96
|
+
puts "Backtrace:"
|
97
|
+
puts e.backtrace
|
98
|
+
@status = :done
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# This method kills all the processes in Processor instances and its own processing thread
|
104
|
+
|
105
|
+
def killall
|
106
|
+
@processors.each do |proc|
|
107
|
+
proc.kill
|
108
|
+
end
|
109
|
+
@processing_thread.kill
|
110
|
+
end
|
111
|
+
|
112
|
+
# This method returns the "to MP3" Processor instance if it exists or nil otherwise
|
113
|
+
|
114
|
+
def mp3_processor
|
115
|
+
ret = nil
|
116
|
+
@processors.each do |proc|
|
117
|
+
if proc.output_type == :mp3
|
118
|
+
ret = proc
|
119
|
+
end
|
120
|
+
end
|
121
|
+
ret
|
122
|
+
end
|
123
|
+
|
124
|
+
# This method returns the "to OGG" Processor instance if it exists or nil otherwise
|
125
|
+
|
126
|
+
def ogg_processor
|
127
|
+
ret = nil
|
128
|
+
@processors.each do |proc|
|
129
|
+
if proc.output_type == :ogg
|
130
|
+
ret = proc
|
131
|
+
end
|
132
|
+
end
|
133
|
+
ret
|
134
|
+
end
|
135
|
+
|
136
|
+
# This method returns the "to WAV" Processor instance if it exists or nil otherwise
|
137
|
+
|
138
|
+
def wav_processor
|
139
|
+
ret = nil
|
140
|
+
@processors.each do |proc|
|
141
|
+
if proc.output_type == :wav
|
142
|
+
ret = proc
|
143
|
+
end
|
144
|
+
end
|
145
|
+
ret
|
146
|
+
end
|
147
|
+
|
148
|
+
# This method returns full input path
|
149
|
+
|
150
|
+
def input
|
151
|
+
@input
|
152
|
+
end
|
153
|
+
|
154
|
+
# This method returns full output file name
|
155
|
+
|
156
|
+
def output_name
|
157
|
+
@output_name
|
158
|
+
end
|
159
|
+
|
160
|
+
# This method returns the path in which output file is saved
|
161
|
+
|
162
|
+
def output_path
|
163
|
+
@output_path
|
164
|
+
end
|
165
|
+
|
166
|
+
# This method returns custom arguments passed to FFmpeg
|
167
|
+
|
168
|
+
def custom_args
|
169
|
+
@custom_args
|
170
|
+
end
|
171
|
+
|
172
|
+
# This method returns percentage of process completion
|
173
|
+
|
174
|
+
def processing_percentage
|
175
|
+
@processing_percentage || 0
|
176
|
+
end
|
177
|
+
|
178
|
+
# This method returns percentage of process completion formatted for output
|
179
|
+
|
180
|
+
def format_processing_percentage
|
181
|
+
@processing_percentage.nil? ? "0%" : @processing_percentage.to_s + "%"
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
data/lib/exceptions.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
module RFF
|
2
|
+
|
3
|
+
# This exception is thrown on insufficient arguments to the method
|
4
|
+
|
5
|
+
class ArgumentError < ::ArgumentError
|
6
|
+
end
|
7
|
+
|
8
|
+
# This exception is thrown on FFmpeg processing error
|
9
|
+
|
10
|
+
class ProcessingFailure < ::RuntimeError
|
11
|
+
|
12
|
+
# Initializes the exception with arguments
|
13
|
+
# * _exitcode_ <b>(required)</b> - FFmpeg exit code
|
14
|
+
# * _msg_ - Message describing the error. Defaults to nil
|
15
|
+
|
16
|
+
def initialize(exitcode, msg=nil)
|
17
|
+
@msg = msg
|
18
|
+
@exitcode = exitcode
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns message describing the error (exit code and describing message if it is present)
|
22
|
+
|
23
|
+
def to_s
|
24
|
+
if msg.nil?
|
25
|
+
exitcode.to_s
|
26
|
+
else
|
27
|
+
msg + exitcode.to_s
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module RFF
|
2
|
+
|
3
|
+
# A class that reads the given IO stream and provides advanced reading functions for it. It reads the given stream to the internal buffer in separate thread and uses this buffer to provide reading functionality that is not available in IO stream alone
|
4
|
+
|
5
|
+
class OutputReader
|
6
|
+
|
7
|
+
# This constructor initializes the class instance with IO stream and starts the stream reading thread
|
8
|
+
# * _io_ - the IO stream to read from
|
9
|
+
|
10
|
+
def initialize io
|
11
|
+
@buffer = ""
|
12
|
+
@writecount = 0
|
13
|
+
@readcount = 0
|
14
|
+
@eof = false
|
15
|
+
@reading_thread = Thread.new do |th|
|
16
|
+
while data = io.read(10)
|
17
|
+
@buffer += data
|
18
|
+
@writecount += data.length
|
19
|
+
end
|
20
|
+
@eof = true
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# This method provides an implementation of IO gets method for streams containing lines with different line separators in some parts
|
25
|
+
# * _seps_ - an array defining the line separators. Defaults to one, default LF separator
|
26
|
+
# Outputs next line from the stream or "EOF\\n" when the stream reaches its end
|
27
|
+
|
28
|
+
def gets seps=["\n"]
|
29
|
+
if @writecount > @readcount
|
30
|
+
line = ""
|
31
|
+
begin
|
32
|
+
c = @buffer[@readcount]
|
33
|
+
if !c.nil?
|
34
|
+
@readcount = @readcount+1
|
35
|
+
line += c
|
36
|
+
if seps.include?(c)
|
37
|
+
break
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end while !@eof
|
41
|
+
line
|
42
|
+
elsif @eof
|
43
|
+
"EOF\n"
|
44
|
+
else
|
45
|
+
nil
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# This method can be used to join the reading thread in some place of the script
|
50
|
+
|
51
|
+
def join_reading_thread
|
52
|
+
@reading_thread.join
|
53
|
+
end
|
54
|
+
|
55
|
+
# This method outputs the internal buffer without any additional processing
|
56
|
+
|
57
|
+
def get_raw_buffer
|
58
|
+
@buffer
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
data/lib/processor.rb
ADDED
@@ -0,0 +1,626 @@
|
|
1
|
+
require_relative 'exceptions'
|
2
|
+
require_relative 'output_reader'
|
3
|
+
require 'open3'
|
4
|
+
require 'time'
|
5
|
+
module RFF
|
6
|
+
|
7
|
+
# The main processing class of the _rff_ gem. It spawns FFmpeg conversion process and parses its output, providing information about input and output files and current process status
|
8
|
+
|
9
|
+
class Processor
|
10
|
+
|
11
|
+
# This constructor initializes the class with the following arguments:
|
12
|
+
# * _input_ <b>(required)</b> - the full path to the input file
|
13
|
+
# * <i>output_type</i> <b>(required)</b> - defines the type of the output. Must be one of [:mp3, :ogg, :wav] for audio conversion or [:mp4, :ogv, :webm] for video conversion
|
14
|
+
# * <i>output_path</i> - a path to place the output file in. Defaults to nil, which means that the input' s directory path is used
|
15
|
+
# * _quality_ - only affects video conversion. Sets the video conversion quality. Defaults to 5000k, which is tested value for good video conversion quality
|
16
|
+
# * <i>custom_args</i> - passes custom arguments to FFmpeg. Defaults to nil, which means no custom arguments are given
|
17
|
+
# * <i>recommended_audio_quality</i> - determines if recommended by FFmpeg community audio quality settings should be used. Defaults to true, which means audio conversion with good, recommended quality. Set to false if you are giving additional arguments that determine this quality.
|
18
|
+
# This method also validates arguments, determines full output name, generates appropriate FFmpeg command, determines conversion type and initializes status (it is :pending at this point).
|
19
|
+
|
20
|
+
def initialize input, output_type, output_path=nil, quality="5000k", custom_args=nil, recommended_audio_quality=true
|
21
|
+
if input.nil? || input.empty? || output_type.nil?
|
22
|
+
raise RFF::ArgumentError.new("Input and output type can not be empty nor nil!")
|
23
|
+
end
|
24
|
+
if ![:mp3, :ogg, :wav, :mp4, :webm, :ogv].include?(output_type.to_sym)
|
25
|
+
raise RFF::ArgumentError.new("Output type must be one of [:mp3, :ogg, :wav, :mp4, :webm, :ogv]!")
|
26
|
+
end
|
27
|
+
@input = input
|
28
|
+
@output_type = output_type
|
29
|
+
@output_name = File.basename(@input).split(".")[0]
|
30
|
+
@output_path = output_path || File.dirname(input)
|
31
|
+
@quality = quality
|
32
|
+
@custom_args = custom_args
|
33
|
+
if [:mp3, :ogg, :wav].include?(@output_type)
|
34
|
+
@command = "ffmpeg -y -i #{@input} -acodec #{@output_type == :mp3 ? "libmp3lame" : (@output_type == :ogg ? "libvorbis" : "pcm_s16le")}#{recommended_audio_quality ? (@output_type == :mp3 ? " -aq 2" : (@output_type == :ogg ? " -aq 4" : "")) : ""}#{@custom_args.nil? ? "" : " #{@custom_args}"} #{@output_path}/#{@output_name}.#{@output_type.to_s}"
|
35
|
+
@conversion_type = :audio
|
36
|
+
else
|
37
|
+
@command = "ffmpeg -y -i #{@input} -acodec #{(@output_type == :webm || @output_type == :ogv) ? "libvorbis" : "aac"} -vcodec #{@output_type == :webm ? "libvpx" : (@output_type == :ogv ? "libtheora" : "mpeg4")}#{@output_type == :mp4 ? " -strict -2" : ""}#{(!@quality.nil? && !@quality.empty?) ? " -b:v #{@quality}" : ""}#{recommended_audio_quality ? (@output_type == :webm || @output_type == :ogv ? " -aq 4" : " -b:a 240k") : ""}#{@custom_args.nil? ? "" : " #{@custom_args}"} #{@output_path}/#{@output_name}.#{@output_type.to_s}"
|
38
|
+
@conversion_type = :video
|
39
|
+
end
|
40
|
+
@status = :pending
|
41
|
+
end
|
42
|
+
|
43
|
+
# This method runs the FFmpeg conversion process in a separate thread. First it initializes processing percentage and then spawns a new thread, in which FFmpeg conversion process is spawned through Open3.popen2e. It sets the processing status, passes the command output to OutputReader instance and initializes all the needed structures for information. Then it parses the output until it ends to extract the information, which is available through this class' getter methods. All the information is filled in as soon as it appears in the command output. When the process finishes, it cleans up the streams, sets percentage to 100% and gets the command' s exit status. Then it sets :completed or :failed status according to the command' s status. At the end it catches and displays any exceptions that can occur in the thread
|
44
|
+
|
45
|
+
def fire
|
46
|
+
@processing_percentage = 0
|
47
|
+
@processing_thread = Thread.new do |th|
|
48
|
+
begin
|
49
|
+
Open3.popen2e(@command) do |progin, progout, progthread|
|
50
|
+
@status = :processing
|
51
|
+
@parser_status = :normal
|
52
|
+
outputreader = OutputReader.new(progout)
|
53
|
+
@rawoutput = []
|
54
|
+
@input_meta_common = {}
|
55
|
+
@input_meta_audio = {}
|
56
|
+
@input_meta_video = {}
|
57
|
+
@output_meta_common = {}
|
58
|
+
@output_meta_audio = {}
|
59
|
+
@output_meta_video = {}
|
60
|
+
@processing_status = {}
|
61
|
+
begin
|
62
|
+
#puts "DEBUG: Processing next line..."
|
63
|
+
line = outputreader.gets(["\n", "\r"])
|
64
|
+
line = line.chomp! if !line.nil?
|
65
|
+
#puts "DEBUG: Line: " + line.to_s
|
66
|
+
#puts "DEBUG: Raw OutputReader buffer content: "
|
67
|
+
#puts outputreader.get_raw_buffer
|
68
|
+
if !line.nil? && line != "EOF"
|
69
|
+
#puts "DEBUG: Adding line to rawoutput..."
|
70
|
+
@rawoutput << line
|
71
|
+
# Getting rid of unnecessary indentation spaces
|
72
|
+
#puts "DEBUG: Removing unnecessary spaces..."
|
73
|
+
if line[/^[ ]+/] != nil
|
74
|
+
line[/^[ ]+/] = ""
|
75
|
+
end
|
76
|
+
if line[/[ ]+/] != nil
|
77
|
+
line[/[ ]+/] = " "
|
78
|
+
end
|
79
|
+
if line[/[ ]+$/] != nil
|
80
|
+
line[/[ ]+$/] = ""
|
81
|
+
end
|
82
|
+
line.gsub!(/=[ ]+/, "=")
|
83
|
+
# Parsing
|
84
|
+
#puts "DEBUG: Line after spaces removal: " + line.to_s
|
85
|
+
#puts "DEBUG: Parsing line..."
|
86
|
+
if @conversion_type == :audio
|
87
|
+
if @parser_status == :meta
|
88
|
+
#puts "DEBUG: Parser in metadata parsing mode"
|
89
|
+
if line[0..7] == "Duration" || line[0..5] == "Stream" || line[0] == "[" || line[0..5] == "Output" || line[0..4] == "Input"
|
90
|
+
@parser_status = :normal
|
91
|
+
else
|
92
|
+
#puts "DEBUG: Reading metadata line..."
|
93
|
+
if @last_met_io == :input
|
94
|
+
@input_meta_audio[line.split(":")[0].downcase[0..-2].to_sym] = line.split(":")[1][1..-1]
|
95
|
+
elsif @last_met_io == :output
|
96
|
+
@output_meta_audio[line.split(":")[0].downcase[0..-2].to_sym] = line.split(":")[1][1..-1]
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
if @parser_status == :strmap
|
101
|
+
#puts "DEBUG: Parser in stream mapping parsing mode"
|
102
|
+
#puts "DEBUG: Reading stream mapping information..."
|
103
|
+
@stream_mapping_audio = line[21..-2]
|
104
|
+
@parser_status = :retnormal
|
105
|
+
end
|
106
|
+
if @parser_status == :normal
|
107
|
+
#puts "DEBUG: Parser in normal mode"
|
108
|
+
if line[0..5] == "ffmpeg"
|
109
|
+
#puts "DEBUG: Approached version line"
|
110
|
+
@ff_versionline = line
|
111
|
+
elsif line[0..4] == "built"
|
112
|
+
#puts "DEBUG: Approached build line"
|
113
|
+
@ff_buildline = line
|
114
|
+
elsif line[0..4] == "Input"
|
115
|
+
#puts "DEBUG: Approached input declaration"
|
116
|
+
@input_type = line.split(",")[1][1..-1]
|
117
|
+
@last_met_io = :input
|
118
|
+
elsif line[0..5] == "Output"
|
119
|
+
#puts "DEBUG: Approached output declaration"
|
120
|
+
@detected_output_type = line.split(",")[1][1..-1]
|
121
|
+
@last_met_io = :output
|
122
|
+
elsif line == "Metadata:"
|
123
|
+
#puts "DEBUG: Approached metadata start"
|
124
|
+
@parser_status = :meta
|
125
|
+
elsif line[0..7] == "Duration"
|
126
|
+
#puts "DEBUG: Approached duration line"
|
127
|
+
@input_duration = line.split(",")[0][10..-1]
|
128
|
+
if line.split(",")[1][1..5] == "start"
|
129
|
+
#puts "DEBUG: Detected start variation of the line"
|
130
|
+
@input_start = line.split(",")[1][6..-1]
|
131
|
+
@input_bitrate = line.split(",")[2][10..-1]
|
132
|
+
else
|
133
|
+
#puts "DEBUG: Detected only bitrate variation of the line"
|
134
|
+
@input_bitrate = line.split(",")[1][10..-1]
|
135
|
+
end
|
136
|
+
elsif line == "Stream mapping:"
|
137
|
+
#puts "DEBUG: Approached stream mapping declaration"
|
138
|
+
@parser_status = :strmap
|
139
|
+
elsif line[0..5] == "Stream"
|
140
|
+
#puts "DEBUG: Approached stream information line"
|
141
|
+
if @last_met_io == :input
|
142
|
+
@audio_input_format = line.split(",")[0][20..-1]
|
143
|
+
@audio_input_freq = line.split(",")[1][1..-1]
|
144
|
+
@audio_input_channelmode = line.split(",")[2][1..-1]
|
145
|
+
@audio_input_format_type = line.split(",")[3][1..-1]
|
146
|
+
if line.split(",")[4] != nil
|
147
|
+
@audio_input_bitrate2 = line.split(",")[4][1..-1]
|
148
|
+
end
|
149
|
+
elsif @last_met_io == :output
|
150
|
+
@audio_output_format = line.split(",")[0][20..-1]
|
151
|
+
@audio_output_freq = line.split(",")[1][1..-1]
|
152
|
+
@audio_output_channelmode = line.split(",")[2][1..-1]
|
153
|
+
@audio_output_format_type = line.split(",")[3][1..-1]
|
154
|
+
if line.split(",")[4] != nil
|
155
|
+
@audio_output_bitrate2 = line.split(",")[4][1..-1]
|
156
|
+
end
|
157
|
+
end
|
158
|
+
elsif line[0..3] == "size"
|
159
|
+
#puts "DEBUG: Approached processing status line"
|
160
|
+
line.split(" ").each do |spl|
|
161
|
+
@processing_status[spl.split("=")[0].to_sym] = spl.split("=")[1]
|
162
|
+
end
|
163
|
+
if @processing_status[:time] != nil && @input_duration != nil
|
164
|
+
@processing_percentage = ((((Time.parse(@processing_status[:time])-Time.parse("0:0"))/(Time.parse(@input_duration)-Time.parse("0:0")))).round(2)*100).to_i #/ This is for jEdit syntax highlighting to fix
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
if @parser_status == :retnormal
|
169
|
+
#puts "DEBUG: Parser returning to normal mode"
|
170
|
+
@parser_status = :normal
|
171
|
+
end
|
172
|
+
elsif @conversion_type == :video
|
173
|
+
if @parser_status == :meta
|
174
|
+
#puts "DEBUG: Parser in metadata parsing mode"
|
175
|
+
if line[0..7] == "Duration" || line[0..5] == "Stream" || line[0] == "[" || line[0..5] == "Output" || line[0..4] == "Input"
|
176
|
+
@parser_status = :normal
|
177
|
+
else
|
178
|
+
#puts "DEBUG: Reading metadata line..."
|
179
|
+
if @last_met_io == :input
|
180
|
+
if @last_stream_type == nil
|
181
|
+
@input_meta_common[line.split(":")[0].downcase[0..-2].to_sym] = line.split(":")[1][1..-1]
|
182
|
+
elsif @last_stream_type == :audio
|
183
|
+
@input_meta_audio[line.split(":")[0].downcase[0..-2].to_sym] = line.split(":")[1][1..-1]
|
184
|
+
elsif @last_stream_type == :video
|
185
|
+
@input_meta_video[line.split(":")[0].downcase[0..-2].to_sym] = line.split(":")[1][1..-1]
|
186
|
+
end
|
187
|
+
elsif @last_met_io == :output
|
188
|
+
if @last_stream_type == nil
|
189
|
+
@output_meta_common[line.split(":")[0].downcase[0..-2].to_sym] = line.split(":")[1][1..-1]
|
190
|
+
elsif @last_stream_type == :audio
|
191
|
+
@output_meta_audio[line.split(":")[0].downcase[0..-2].to_sym] = line.split(":")[1][1..-1]
|
192
|
+
elsif @last_stream_type == :video
|
193
|
+
@output_meta_video[line.split(":")[0].downcase[0..-2].to_sym] = line.split(":")[1][1..-1]
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
if @parser_status == :strmap
|
199
|
+
#puts "DEBUG: Parser in stream mapping parsing mode"
|
200
|
+
#puts "DEBUG: Reading stream mapping information..."
|
201
|
+
@stream_mapping_video = line[21..-2]
|
202
|
+
@parser_status = :strmap2
|
203
|
+
elsif @parser_status == :strmap2
|
204
|
+
@stream_mapping_audio = line[21..-2]
|
205
|
+
@parser_status = :retnormal
|
206
|
+
end
|
207
|
+
if @parser_status == :normal
|
208
|
+
#puts "DEBUG: Parser in normal mode"
|
209
|
+
if line[0..5] == "ffmpeg"
|
210
|
+
#puts "DEBUG: Approached version line"
|
211
|
+
@ff_versionline = line
|
212
|
+
elsif line[0..4] == "built"
|
213
|
+
#puts "DEBUG: Approached build line"
|
214
|
+
@ff_buildline = line
|
215
|
+
elsif line[0..4] == "Input"
|
216
|
+
#puts "DEBUG: Approached input declaration"
|
217
|
+
@input_type = line.split(",")[1][1..-1]
|
218
|
+
@last_met_io = :input
|
219
|
+
@last_stream_type = nil
|
220
|
+
elsif line[0..5] == "Output"
|
221
|
+
#puts "DEBUG: Approached output declaration"
|
222
|
+
@detected_output_type = line.split(",")[1][1..-1]
|
223
|
+
@last_met_io = :output
|
224
|
+
@last_stream_type = nil
|
225
|
+
elsif line == "Metadata:"
|
226
|
+
#puts "DEBUG: Approached metadata start"
|
227
|
+
@parser_status = :meta
|
228
|
+
elsif line[0..7] == "Duration"
|
229
|
+
#puts "DEBUG: Approached duration line"
|
230
|
+
@input_duration = line.split(",")[0][10..-1]
|
231
|
+
if line.split(",")[1][1..5] == "start"
|
232
|
+
#puts "DEBUG: Detected start variation of the line"
|
233
|
+
@input_start = line.split(",")[1][8..-1]
|
234
|
+
@input_bitrate = line.split(",")[2][10..-1]
|
235
|
+
else
|
236
|
+
#puts "DEBUG: Detected only bitrate variation of the line"
|
237
|
+
@input_bitrate = line.split(",")[1][10..-1]
|
238
|
+
end
|
239
|
+
elsif line == "Stream mapping:"
|
240
|
+
#puts "DEBUG: Approached stream mapping declaration"
|
241
|
+
@parser_status = :strmap
|
242
|
+
elsif line[0..5] == "Stream"
|
243
|
+
#puts "DEBUG: Approached stream information line"
|
244
|
+
if line[13..17] == "Video"
|
245
|
+
@last_stream_type = :video
|
246
|
+
elsif line[13..17] == "Audio"
|
247
|
+
@last_stream_type = :audio
|
248
|
+
else
|
249
|
+
@last_stream_type = nil
|
250
|
+
end
|
251
|
+
if @last_met_io == :input
|
252
|
+
if @last_stream_type == :video
|
253
|
+
@video_input_format = line.split(",")[0][20..-1]
|
254
|
+
@video_input_colorspace = line.split(",")[1][1..-1]
|
255
|
+
@video_input_resolution = line.split(",")[2][1..-1]
|
256
|
+
@video_input_additional = line.split(",")[3..-1]
|
257
|
+
elsif @last_stream_type == :audio
|
258
|
+
@audio_input_format = line.split(",")[0][20..-1]
|
259
|
+
@audio_input_freq = line.split(",")[1][1..-1]
|
260
|
+
@audio_input_channelmode = line.split(",")[2][1..-1]
|
261
|
+
@audio_input_format_type = line.split(",")[3][1..-1]
|
262
|
+
if line.split(",")[4] != nil
|
263
|
+
@audio_input_bitrate2 = line.split(",")[4][1..-1]
|
264
|
+
end
|
265
|
+
end
|
266
|
+
elsif @last_met_io == :output
|
267
|
+
if @last_stream_type == :video
|
268
|
+
@video_output_format = line.split(",")[0][20..-1]
|
269
|
+
@video_output_colorspace = line.split(",")[1][1..-1]
|
270
|
+
@video_output_resolution = line.split(",")[2][1..-1]
|
271
|
+
@video_output_additional = line.split(",")[3..-1]
|
272
|
+
elsif @last_stream_type == :audio
|
273
|
+
@audio_output_format = line.split(",")[0][20..-1]
|
274
|
+
@audio_output_freq = line.split(",")[1][1..-1]
|
275
|
+
@audio_output_channelmode = line.split(",")[2][1..-1]
|
276
|
+
@audio_output_format_type = line.split(",")[3][1..-1]
|
277
|
+
if line.split(",")[4] != nil
|
278
|
+
@audio_output_bitrate2 = line.split(",")[4][1..-1]
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
282
|
+
elsif line[0..4] == "frame"
|
283
|
+
#puts "DEBUG: Approached processing status line"
|
284
|
+
line.split(" ").each do |spl|
|
285
|
+
@processing_status[spl.split("=")[0].to_sym] = spl.split("=")[1]
|
286
|
+
end
|
287
|
+
if @processing_status[:time] != nil && @input_duration != nil
|
288
|
+
@processing_percentage = ((((Time.parse(@processing_status[:time])-Time.parse("0:0"))/(Time.parse(@input_duration)-Time.parse("0:0")))).round(2)*100).to_i #/ This is for jEdit syntax highlighting to fix
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
292
|
+
if @parser_status == :retnormal
|
293
|
+
#puts "DEBUG: Parser returning to normal mode"
|
294
|
+
@parser_status = :normal
|
295
|
+
end
|
296
|
+
end
|
297
|
+
end
|
298
|
+
end while line != "EOF"
|
299
|
+
#puts "DEBUG: After EOF, closing streams..."
|
300
|
+
progout.close
|
301
|
+
progin.close
|
302
|
+
progthread.join
|
303
|
+
progst = progthread.value
|
304
|
+
@exit_status = progst.exitstatus
|
305
|
+
#puts "Got output status: #{progst.exitstatus}"
|
306
|
+
if progst.success?
|
307
|
+
@status = :completed
|
308
|
+
@processing_percentage = 100
|
309
|
+
else
|
310
|
+
@status = :failed
|
311
|
+
end
|
312
|
+
end
|
313
|
+
if @status == :failed
|
314
|
+
raise RFF::ProcessingFailure.new(@exit_status, "Inspect the output as FFmpeg returned with status: ")
|
315
|
+
end
|
316
|
+
rescue => e
|
317
|
+
puts "Caught exception: " + e.to_s
|
318
|
+
puts "Backtrace:"
|
319
|
+
puts e.backtrace
|
320
|
+
@status = :failed
|
321
|
+
end
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
# This method returns full input path
|
326
|
+
|
327
|
+
def input
|
328
|
+
@input
|
329
|
+
end
|
330
|
+
|
331
|
+
# This method returns output type read from the filename
|
332
|
+
|
333
|
+
def output_type
|
334
|
+
@output_type
|
335
|
+
end
|
336
|
+
|
337
|
+
# This method returns output type read by FFmpeg
|
338
|
+
|
339
|
+
def detected_output_type
|
340
|
+
@detected_output_type
|
341
|
+
end
|
342
|
+
|
343
|
+
# This method returns full output name
|
344
|
+
|
345
|
+
def output_name
|
346
|
+
@output_name
|
347
|
+
end
|
348
|
+
|
349
|
+
# This method returns path where the output is (being) saved
|
350
|
+
|
351
|
+
def output_path
|
352
|
+
@output_path
|
353
|
+
end
|
354
|
+
|
355
|
+
# This method returns used video quality
|
356
|
+
|
357
|
+
def quality
|
358
|
+
@quality
|
359
|
+
end
|
360
|
+
|
361
|
+
# This method returns the FFmpeg command used for conversion
|
362
|
+
|
363
|
+
def command
|
364
|
+
@command
|
365
|
+
end
|
366
|
+
|
367
|
+
# This method returns custom arguments passed to FFmpeg
|
368
|
+
|
369
|
+
def custom_args
|
370
|
+
@custom_args
|
371
|
+
end
|
372
|
+
|
373
|
+
# This method returns conversion type (:audio or :video)
|
374
|
+
|
375
|
+
def conversion_type
|
376
|
+
@conversion_type
|
377
|
+
end
|
378
|
+
|
379
|
+
# This method returns full path to the output file
|
380
|
+
|
381
|
+
def full_output_path
|
382
|
+
"#{@output_path}/#{@output_name}.#{@output_type.to_s}"
|
383
|
+
end
|
384
|
+
|
385
|
+
# This method returns raw command output as an array of lines after getting rid of unneeded whitespaces
|
386
|
+
|
387
|
+
def raw_command_output
|
388
|
+
@rawoutput
|
389
|
+
end
|
390
|
+
|
391
|
+
# This method returns current processing status (:pending, :processing, :completed, :failed, :aborted)
|
392
|
+
|
393
|
+
def status
|
394
|
+
@status
|
395
|
+
end
|
396
|
+
|
397
|
+
# This method returns current output parser status
|
398
|
+
|
399
|
+
def parser_status
|
400
|
+
@parser_status
|
401
|
+
end
|
402
|
+
|
403
|
+
# This method returns common metadata for input streams as a hash with keys being symbols representing each metadata downcased name
|
404
|
+
|
405
|
+
def common_input_metadata
|
406
|
+
@input_meta_common
|
407
|
+
end
|
408
|
+
|
409
|
+
# This method returns metadata for audio input stream as a hash with keys being symbols representing each metadata downcased name
|
410
|
+
|
411
|
+
def audio_input_metadata
|
412
|
+
@input_meta_audio
|
413
|
+
end
|
414
|
+
|
415
|
+
# This method returns metadata for video input stream as a hash with keys being symbols representing each metadata downcased name
|
416
|
+
|
417
|
+
def video_input_metadata
|
418
|
+
@input_meta_video
|
419
|
+
end
|
420
|
+
|
421
|
+
# This method returns common metadata for output streams as a hash with keys being symbols representing each metadata downcased name
|
422
|
+
|
423
|
+
def common_output_metadata
|
424
|
+
@output_meta_common
|
425
|
+
end
|
426
|
+
|
427
|
+
# This method returns metadata for audio output stream as a hash with keys being symbols representing each metadata downcased name
|
428
|
+
|
429
|
+
def audio_output_metadata
|
430
|
+
@output_meta_audio
|
431
|
+
end
|
432
|
+
|
433
|
+
# This method returns metadata for video output stream as a hash with keys being symbols representing each metadata downcased name
|
434
|
+
|
435
|
+
def video_output_metadata
|
436
|
+
@output_meta_video
|
437
|
+
end
|
438
|
+
|
439
|
+
# This method returns a hash which represents current processing status (eg. frames processed, time processed etc.) with keys being symbols representing each status value
|
440
|
+
|
441
|
+
def processing_status
|
442
|
+
@processing_status
|
443
|
+
end
|
444
|
+
|
445
|
+
# This method returns audio stream mapping information (input_format -> output_format)
|
446
|
+
|
447
|
+
def audio_stream_mapping
|
448
|
+
@stream_mapping_audio
|
449
|
+
end
|
450
|
+
|
451
|
+
# This method returns video stream mapping information (input_format -> output_format)
|
452
|
+
|
453
|
+
def video_stream_mapping
|
454
|
+
@stream_mapping_video
|
455
|
+
end
|
456
|
+
|
457
|
+
# This method returns FFmpeg version line
|
458
|
+
|
459
|
+
def ffmpeg_version_line
|
460
|
+
@ff_versionline
|
461
|
+
end
|
462
|
+
|
463
|
+
# This method returns FFmpeg build line
|
464
|
+
|
465
|
+
def ffmpeg_build_line
|
466
|
+
@ff_buildline
|
467
|
+
end
|
468
|
+
|
469
|
+
# This method returns input type detected by FFmpeg
|
470
|
+
|
471
|
+
def input_type
|
472
|
+
@input_type
|
473
|
+
end
|
474
|
+
|
475
|
+
# This method returns input duration
|
476
|
+
|
477
|
+
def input_duration
|
478
|
+
@input_duration
|
479
|
+
end
|
480
|
+
|
481
|
+
# This method returns start point of the input
|
482
|
+
|
483
|
+
def input_start
|
484
|
+
@input_start
|
485
|
+
end
|
486
|
+
|
487
|
+
# This method returns input bitrate (from the duration line)
|
488
|
+
|
489
|
+
def input_bitrate
|
490
|
+
@input_bitrate
|
491
|
+
end
|
492
|
+
|
493
|
+
# This method returns format of audio input
|
494
|
+
|
495
|
+
def audio_input_format
|
496
|
+
@audio_input_format
|
497
|
+
end
|
498
|
+
|
499
|
+
# This method returns frequency of audio input
|
500
|
+
|
501
|
+
def audio_input_frequency
|
502
|
+
@audio_input_freq
|
503
|
+
end
|
504
|
+
|
505
|
+
# This method returns channel mode (eg. mono, stereo) of audio input
|
506
|
+
|
507
|
+
def audio_input_channelmode
|
508
|
+
@audio_input_channelmode
|
509
|
+
end
|
510
|
+
|
511
|
+
# This method returns type of format of audio input
|
512
|
+
|
513
|
+
def audio_input_format_type
|
514
|
+
@audio_input_format_type
|
515
|
+
end
|
516
|
+
|
517
|
+
# This method returns bitrate of audio input (from input information line)
|
518
|
+
|
519
|
+
def audio_input_bitrate2
|
520
|
+
@audio_input_bitrate2
|
521
|
+
end
|
522
|
+
|
523
|
+
# This method returns format of audio output
|
524
|
+
|
525
|
+
def audio_output_format
|
526
|
+
@audio_output_format
|
527
|
+
end
|
528
|
+
|
529
|
+
# This method returns frequency of audio output
|
530
|
+
|
531
|
+
def audio_output_frequency
|
532
|
+
@audio_output_freq
|
533
|
+
end
|
534
|
+
|
535
|
+
# This method returns channel mode (eg. mono, stereo) of audio output
|
536
|
+
|
537
|
+
def audio_output_channelmode
|
538
|
+
@audio_output_channelmode
|
539
|
+
end
|
540
|
+
|
541
|
+
# This method returns type of format of audio output
|
542
|
+
|
543
|
+
def audio_output_format_type
|
544
|
+
@audio_output_format_type
|
545
|
+
end
|
546
|
+
|
547
|
+
# This method returns bitrate of audio output (from output information line)
|
548
|
+
|
549
|
+
def audio_output_bitrate2
|
550
|
+
@audio_output_bitrate2
|
551
|
+
end
|
552
|
+
|
553
|
+
# This method returns format of video input
|
554
|
+
|
555
|
+
def video_input_format
|
556
|
+
@video_input_format
|
557
|
+
end
|
558
|
+
|
559
|
+
# This method returns color space of video input
|
560
|
+
|
561
|
+
def video_input_colorspace
|
562
|
+
@video_input_colorspace
|
563
|
+
end
|
564
|
+
|
565
|
+
# This method returns resolution of video input
|
566
|
+
|
567
|
+
def video_input_resolution
|
568
|
+
@video_input_resolution
|
569
|
+
end
|
570
|
+
|
571
|
+
# This method returns additional information about video input as an array of values
|
572
|
+
|
573
|
+
def video_input_additional
|
574
|
+
@video_input_additional
|
575
|
+
end
|
576
|
+
|
577
|
+
# This method returns format of video output
|
578
|
+
|
579
|
+
def video_output_format
|
580
|
+
@video_output_format
|
581
|
+
end
|
582
|
+
|
583
|
+
# This method returns color space of video output
|
584
|
+
|
585
|
+
def video_output_colorspace
|
586
|
+
@video_output_colorspace
|
587
|
+
end
|
588
|
+
|
589
|
+
# This method returns resolution of video output
|
590
|
+
|
591
|
+
def video_output_resolution
|
592
|
+
@video_output_resolution
|
593
|
+
end
|
594
|
+
|
595
|
+
# This method returns additional information about video output as an array of values
|
596
|
+
|
597
|
+
def video_output_additional
|
598
|
+
@video_output_additional
|
599
|
+
end
|
600
|
+
|
601
|
+
# This method returns percentage of process completion
|
602
|
+
|
603
|
+
def processing_percentage
|
604
|
+
@processing_percentage || 0
|
605
|
+
end
|
606
|
+
|
607
|
+
# This method returns percentage of process completion formatted for output
|
608
|
+
|
609
|
+
def format_processing_percentage
|
610
|
+
@processing_percentage.nil? ? "0%" : @processing_percentage.to_s + "%"
|
611
|
+
end
|
612
|
+
|
613
|
+
# This method returns the exit status of the FFmpeg command
|
614
|
+
|
615
|
+
def command_exit_status
|
616
|
+
@exit_status
|
617
|
+
end
|
618
|
+
|
619
|
+
# This method kills processing thread and sets status to :aborted
|
620
|
+
|
621
|
+
def kill
|
622
|
+
@processing_thread.kill
|
623
|
+
@status = :aborted
|
624
|
+
end
|
625
|
+
end
|
626
|
+
end
|
data/lib/rff.rb
ADDED
@@ -0,0 +1,187 @@
|
|
1
|
+
require_relative 'processor'
|
2
|
+
|
3
|
+
module RFF
|
4
|
+
|
5
|
+
# This class provides an "All video to HTML5" conversion functionality. It takes every compatible with FFmpeg video format and converts it to the three HTML5 video formats - mp4, ogv and webm. If the input is already in one of these formats it is only converted to the two other formats, because it can be used as one of HTML5 sources.
|
6
|
+
|
7
|
+
class VideoHandler
|
8
|
+
|
9
|
+
# This constructor initializes the class with the following arguments:
|
10
|
+
# * _input_ <b>(required)</b> - the full path to the input file
|
11
|
+
# * <i>output_path</i> - a path to place the output file in. Defaults to nil, which means that the input' s directory path is used
|
12
|
+
# * _quality_ - only affects video conversion. Sets the video conversion quality. Defaults to 5000k, which is tested value for good video conversion quality
|
13
|
+
# * <i>custom_args</i> - passes custom arguments to FFmpeg. Defaults to nil, which means no custom arguments are given
|
14
|
+
# * <i>recommended_audio_quality</i> - determines if recommended by FFmpeg community audio quality settings should be used. Defaults to true, which means audio conversion with good, recommended quality. Set to false if you are giving additional arguments that determine this quality.
|
15
|
+
# All of the arguments are passed on to underlying Processor instances. This method also determines input type, initializes processing percentage and creates needed Processor instances.
|
16
|
+
|
17
|
+
def initialize input, output_path=nil, quality="5000k", custom_args=nil, recommended_audio_quality=true
|
18
|
+
@input = input
|
19
|
+
@input_type = File.basename(@input).split(".")[1]
|
20
|
+
@output_path = output_path
|
21
|
+
@quality = quality
|
22
|
+
@custom_args = custom_args
|
23
|
+
@processing_percentage = 0
|
24
|
+
@processors = []
|
25
|
+
types = [:mp4, :ogv, :webm]
|
26
|
+
if types.include?(@input_type.to_sym)
|
27
|
+
types.delete(@input_type.to_sym)
|
28
|
+
end
|
29
|
+
types.each do |type|
|
30
|
+
@processors << RFF::Processor.new(@input, type, @output_path, @quality, @custom_args, recommended_audio_quality)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# This method fires all the Processor instances (conversion processes) in a separate thread at once. Then it counts the overall processing percentage from all the Processor instances as the process goes and sets it to 100% on finish
|
35
|
+
|
36
|
+
def fire_all
|
37
|
+
@processing_thread = Thread.new do |th|
|
38
|
+
begin
|
39
|
+
@processors.each do |proc|
|
40
|
+
proc.fire
|
41
|
+
#sleep(5)
|
42
|
+
end
|
43
|
+
status = :processing
|
44
|
+
while status != :done
|
45
|
+
donecount = 0
|
46
|
+
@processors.each do |proc|
|
47
|
+
#puts "Process status:" + proc.status.to_s
|
48
|
+
if proc.status == :completed || proc.status == :failed || proc.status == :aborted
|
49
|
+
donecount = donecount + 1
|
50
|
+
end
|
51
|
+
end
|
52
|
+
#puts "Done count: " + donecount.to_s
|
53
|
+
if donecount == @processors.count
|
54
|
+
status = :done
|
55
|
+
break
|
56
|
+
end
|
57
|
+
processing_percentage = 0
|
58
|
+
@processors.each do |proc|
|
59
|
+
processing_percentage += proc.processing_percentage
|
60
|
+
end
|
61
|
+
@processing_percentage = (processing_percentage.to_f/@processors.count).to_i
|
62
|
+
end
|
63
|
+
@processing_percentage = 100
|
64
|
+
rescue => e
|
65
|
+
puts "Caught exception: " + e.to_s
|
66
|
+
puts "Backtrace:"
|
67
|
+
puts e.backtrace
|
68
|
+
@status = :done
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# This method fires all the Processor instances (conversion processes) in a separate thread sequentially - next Processor in the row is fired only after the Processor before finishes. It also counts the overall processing percentage from all the Processor instances as the process goes and sets it to 100% on finish
|
74
|
+
|
75
|
+
def fire_sequential
|
76
|
+
@processing_thread = Thread.new do |th|
|
77
|
+
begin
|
78
|
+
i = 0
|
79
|
+
@processors.each do |proc|
|
80
|
+
proc.fire
|
81
|
+
sleep(1)
|
82
|
+
while proc.status == :processing
|
83
|
+
if proc.processing_percentage != nil
|
84
|
+
@processing_percentage = (i*(100/@processors.count))+(proc.processing_percentage.to_f/@processors.count).to_i
|
85
|
+
end
|
86
|
+
end
|
87
|
+
i = i+1
|
88
|
+
#sleep(5)
|
89
|
+
end
|
90
|
+
@processing_percentage = 100
|
91
|
+
rescue => e
|
92
|
+
puts "Caught exception: " + e.to_s
|
93
|
+
puts "Backtrace:"
|
94
|
+
puts e.backtrace
|
95
|
+
@status = :done
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# This method kills all the processes in Processor instances and its own processing thread
|
101
|
+
|
102
|
+
def killall
|
103
|
+
@processors.each do |proc|
|
104
|
+
proc.kill
|
105
|
+
end
|
106
|
+
@processing_thread.kill
|
107
|
+
end
|
108
|
+
|
109
|
+
# This method returns the "to MP4" Processor instance if it exists or nil otherwise
|
110
|
+
|
111
|
+
def mp4_processor
|
112
|
+
ret = nil
|
113
|
+
@processors.each do |proc|
|
114
|
+
if proc.output_type == :mp4
|
115
|
+
ret = proc
|
116
|
+
end
|
117
|
+
end
|
118
|
+
ret
|
119
|
+
end
|
120
|
+
|
121
|
+
# This method returns the "to OGV" Processor instance if it exists or nil otherwise
|
122
|
+
|
123
|
+
def ogv_processor
|
124
|
+
ret = nil
|
125
|
+
@processors.each do |proc|
|
126
|
+
if proc.output_type == :ogv
|
127
|
+
ret = proc
|
128
|
+
end
|
129
|
+
end
|
130
|
+
ret
|
131
|
+
end
|
132
|
+
|
133
|
+
# This method returns the "to WEBM" Processor instance if it exists or nil otherwise
|
134
|
+
|
135
|
+
def webm_processor
|
136
|
+
ret = nil
|
137
|
+
@processors.each do |proc|
|
138
|
+
if proc.output_type == :webm
|
139
|
+
ret = proc
|
140
|
+
end
|
141
|
+
end
|
142
|
+
ret
|
143
|
+
end
|
144
|
+
|
145
|
+
# This method returns full input path
|
146
|
+
|
147
|
+
def input
|
148
|
+
@input
|
149
|
+
end
|
150
|
+
|
151
|
+
# This method returns full output file name
|
152
|
+
|
153
|
+
def output_name
|
154
|
+
@output_name
|
155
|
+
end
|
156
|
+
|
157
|
+
# This method returns the path in which output file is saved
|
158
|
+
|
159
|
+
def output_path
|
160
|
+
@output_path
|
161
|
+
end
|
162
|
+
|
163
|
+
# This method returns used video quality
|
164
|
+
|
165
|
+
def quality
|
166
|
+
@quality
|
167
|
+
end
|
168
|
+
|
169
|
+
# This method returns custom arguments passed to FFmpeg
|
170
|
+
|
171
|
+
def custom_args
|
172
|
+
@custom_args
|
173
|
+
end
|
174
|
+
|
175
|
+
# This method returns percentage of process completion
|
176
|
+
|
177
|
+
def processing_percentage
|
178
|
+
@processing_percentage || 0
|
179
|
+
end
|
180
|
+
|
181
|
+
# This method returns percentage of process completion formatted for output
|
182
|
+
|
183
|
+
def format_processing_percentage
|
184
|
+
@processing_percentage.nil? ? "0%" : @processing_percentage.to_s + "%"
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
metadata
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rff
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '0.2'
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Phitherek_
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-04-04 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: This gem provides a simple Ruby interface to FFmpeg enabling users to
|
14
|
+
convert audio and video to HTML5 supported formats and monitor the process as it
|
15
|
+
goes.
|
16
|
+
email: phitherek@gmail.com
|
17
|
+
executables: []
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- lib/audio_handler.rb
|
22
|
+
- lib/exceptions.rb
|
23
|
+
- lib/output_reader.rb
|
24
|
+
- lib/processor.rb
|
25
|
+
- lib/rff.rb
|
26
|
+
- lib/video_handler.rb
|
27
|
+
homepage: https://github.com/Phitherek/rff
|
28
|
+
licenses: []
|
29
|
+
metadata: {}
|
30
|
+
post_install_message: The 0.2 version of rff has fixed a very important bug! Please
|
31
|
+
do not use version 0.1 of this gem!
|
32
|
+
rdoc_options: []
|
33
|
+
require_paths:
|
34
|
+
- lib
|
35
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - '>='
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: 1.9.2
|
40
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
41
|
+
requirements:
|
42
|
+
- - '>='
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: '0'
|
45
|
+
requirements:
|
46
|
+
- ffmpeg
|
47
|
+
rubyforge_project:
|
48
|
+
rubygems_version: 2.2.2
|
49
|
+
signing_key:
|
50
|
+
specification_version: 4
|
51
|
+
summary: A simple Ruby audio/video converter to HTML5 formats using FFmpeg
|
52
|
+
test_files: []
|