axtro-rvideo 0.9.6
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/CHANGELOG +70 -0
- data/ENV +100 -0
- data/ENV2 +129 -0
- data/LICENSE +20 -0
- data/Manifest +67 -0
- data/README +91 -0
- data/RULES +11 -0
- data/Rakefile +63 -0
- data/axtro-rvideo.gemspec +36 -0
- data/config/boot.rb +25 -0
- data/lib/rvideo.rb +44 -0
- data/lib/rvideo/errors.rb +24 -0
- data/lib/rvideo/float.rb +7 -0
- data/lib/rvideo/frame_capturer.rb +129 -0
- data/lib/rvideo/inspector.rb +483 -0
- data/lib/rvideo/reporter.rb +176 -0
- data/lib/rvideo/reporter/views/index.html.erb +27 -0
- data/lib/rvideo/reporter/views/report.css +27 -0
- data/lib/rvideo/reporter/views/report.html.erb +81 -0
- data/lib/rvideo/reporter/views/report.js +9 -0
- data/lib/rvideo/string.rb +5 -0
- data/lib/rvideo/tools/abstract_tool.rb +414 -0
- data/lib/rvideo/tools/ffmpeg.rb +286 -0
- data/lib/rvideo/tools/ffmpeg2theora.rb +42 -0
- data/lib/rvideo/tools/flvtool2.rb +50 -0
- data/lib/rvideo/tools/mencoder.rb +103 -0
- data/lib/rvideo/tools/mp4box.rb +21 -0
- data/lib/rvideo/tools/mp4creator.rb +35 -0
- data/lib/rvideo/tools/mplayer.rb +31 -0
- data/lib/rvideo/tools/qtfaststart.rb +37 -0
- data/lib/rvideo/tools/yamdi.rb +44 -0
- data/lib/rvideo/transcoder.rb +120 -0
- data/lib/rvideo/version.rb +9 -0
- data/rvideo.gemspec +36 -0
- data/scripts/txt2html +67 -0
- data/setup.rb +1585 -0
- data/spec/files/boat.avi +0 -0
- data/spec/files/kites.mp4 +0 -0
- data/spec/fixtures/ffmpeg_builds.yml +28 -0
- data/spec/fixtures/ffmpeg_results.yml +608 -0
- data/spec/fixtures/files.yml +398 -0
- data/spec/fixtures/recipes.yml +58 -0
- data/spec/integrations/formats_spec.rb +315 -0
- data/spec/integrations/frame_capturer_spec.rb +26 -0
- data/spec/integrations/inspection_spec.rb +112 -0
- data/spec/integrations/recipes_spec.rb +0 -0
- data/spec/integrations/rvideo_spec.rb +17 -0
- data/spec/integrations/transcoder_integration_spec.rb +29 -0
- data/spec/integrations/transcoding_spec.rb +9 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +16 -0
- data/spec/support.rb +36 -0
- data/spec/units/abstract_tool_spec.rb +123 -0
- data/spec/units/ffmpeg_spec.rb +327 -0
- data/spec/units/flvtool2_spec.rb +324 -0
- data/spec/units/frame_capturer_spec.rb +72 -0
- data/spec/units/inspector_spec.rb +59 -0
- data/spec/units/mencoder_spec.rb +4994 -0
- data/spec/units/mp4box_spec.rb +34 -0
- data/spec/units/mp4creator_spec.rb +34 -0
- data/spec/units/mplayer_spec.rb +34 -0
- data/spec/units/qtfaststart_spec.rb +35 -0
- data/spec/units/string_spec.rb +8 -0
- data/spec/units/transcoder_spec.rb +156 -0
- data/tasks/deployment.rake +5 -0
- data/tasks/testing.rake +27 -0
- data/tasks/transcoding.rake +40 -0
- data/tasks/website.rake +8 -0
- metadata +178 -0
|
File without changes
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + "/../spec_helper"
|
|
2
|
+
|
|
3
|
+
module RVideo
|
|
4
|
+
describe RVideo, " with every recipe and file" do
|
|
5
|
+
it "should interpolate commands correctly" do
|
|
6
|
+
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it "should parse prepopulated output successfully" do
|
|
10
|
+
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "should transcode to a viewable file" do
|
|
14
|
+
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
|
2
|
+
|
|
3
|
+
module RVideo
|
|
4
|
+
describe "The entire system should work together" do
|
|
5
|
+
it "with kites.mp4" do
|
|
6
|
+
output_file = "#{TEMP_PATH}/kites.flv"
|
|
7
|
+
FileUtils.rm_f(output_file)
|
|
8
|
+
FileTest.exist?(output_file).should_not be_true
|
|
9
|
+
transcoder = Transcoder.new(spec_file("kites.mp4"))
|
|
10
|
+
transcoder.original.class.should == Inspector
|
|
11
|
+
transcoder.original.duration.should == 19600
|
|
12
|
+
transcoder.execute(recipes('flash_300')['command'], {:output_file => output_file})
|
|
13
|
+
FileTest.exist?(output_file).should be_true
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# it "with The Michael Scott Story" do
|
|
17
|
+
# file = 'michael_scott_story.mov'
|
|
18
|
+
# output_file = "#{TEMP_PATH}/#{file}.flv"
|
|
19
|
+
# FileUtils.rm_f(output_file)
|
|
20
|
+
# FileTest.exist?(output_file).should_not be_true
|
|
21
|
+
# transcoder = Transcoder.new("#{TEST_FILE_PATH}/#{file}")
|
|
22
|
+
# transcoder.original.class.should == Inspector
|
|
23
|
+
# transcoder.original.duration.should == 30400
|
|
24
|
+
# transcoder.execute(recipes('one_pass')['command'], {:output_file => output_file})
|
|
25
|
+
# FileTest.exist?(output_file).should be_true
|
|
26
|
+
# end
|
|
27
|
+
|
|
28
|
+
end
|
|
29
|
+
end
|
data/spec/spec.opts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
--color
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/../lib/rvideo'
|
|
2
|
+
|
|
3
|
+
# Because rspec's assertion style is a stupid, giant
|
|
4
|
+
# fucking waste of time. It's true!
|
|
5
|
+
require 'spec/interop/test'
|
|
6
|
+
require File.dirname(__FILE__) + "/support"
|
|
7
|
+
|
|
8
|
+
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
|
9
|
+
# NOTE some expectations in these specs may rely on behavior #
|
|
10
|
+
# not present in your local build of ffmpeg. #
|
|
11
|
+
# #
|
|
12
|
+
# Any work on supporting multiple builds packaged with the tests #
|
|
13
|
+
# would be accepted, but ffmpeg itself does not support old versions #
|
|
14
|
+
# so it might be best to upgrade if you want to rely on the accuracy of #
|
|
15
|
+
# these tests. #
|
|
16
|
+
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
data/spec/support.rb
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
###
|
|
2
|
+
|
|
3
|
+
FIXTURE_PATH = File.expand_path(File.dirname(__FILE__) + '/../spec/fixtures')
|
|
4
|
+
|
|
5
|
+
LOG_PATH = File.join(File.dirname(__FILE__), "spec.log")
|
|
6
|
+
RVideo.logger = Logger.new LOG_PATH
|
|
7
|
+
|
|
8
|
+
###
|
|
9
|
+
|
|
10
|
+
def ffmpeg(key)
|
|
11
|
+
load_fixture(:ffmpeg_builds)[key.to_s]['response']
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def files(key)
|
|
15
|
+
load_fixture(:files)[key.to_s]['response']
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def recipes(key)
|
|
19
|
+
load_fixture(:recipes)[key.to_s]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# The strip in here is important as the result parsing is apparently
|
|
23
|
+
# quite fussy about leading or trailing whitespace.
|
|
24
|
+
def ffmpeg_result(key)
|
|
25
|
+
load_fixture(:ffmpeg_results)[key.to_s].strip
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
###
|
|
29
|
+
|
|
30
|
+
def load_fixture(name)
|
|
31
|
+
YAML.load_file("#{FIXTURE_PATH}/#{name}.yml")
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def spec_file(name)
|
|
35
|
+
File.expand_path File.join(File.dirname(__FILE__), "files", name)
|
|
36
|
+
end
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
|
2
|
+
|
|
3
|
+
module RVideo
|
|
4
|
+
module Tools
|
|
5
|
+
describe AbstractTool, "#assign" do
|
|
6
|
+
|
|
7
|
+
before do
|
|
8
|
+
@command = "ffmpeg -i $input_file$ $output_file$"
|
|
9
|
+
@options = {
|
|
10
|
+
:input_file => spec_file("kites.mp4"), # "foo",
|
|
11
|
+
:output_file => "bar"
|
|
12
|
+
}
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it "should assign commands properly with options - ffmpeg" do
|
|
16
|
+
Ffmpeg.should_receive(:new).with(@command, @options)
|
|
17
|
+
AbstractTool.assign(@command, @options)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it "should assign properly without options - ffmpeg" do
|
|
21
|
+
Ffmpeg.should_receive(:new).with(@command, {})
|
|
22
|
+
AbstractTool.assign(@command)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "should return an instance of the specified tool" do
|
|
26
|
+
tool = AbstractTool.assign(@command, @options)
|
|
27
|
+
tool.class.should == Ffmpeg
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
describe AbstractTool, " when building a command" do
|
|
32
|
+
|
|
33
|
+
before do
|
|
34
|
+
@options = {
|
|
35
|
+
:input_file => spec_file("kites.mp4"), #"foo",
|
|
36
|
+
:output_file => "bar",
|
|
37
|
+
:resolution => "copy"
|
|
38
|
+
}
|
|
39
|
+
@simple_avi = "ffmpeg -i $input_file$ -ar 44100 -ab 64 -vcodec xvid -acodec mp3 -r 29.97 -y $output_file$"
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "should set supported options successfully" do
|
|
43
|
+
ffmpeg = Ffmpeg.new(@simple_avi, @options)
|
|
44
|
+
ffmpeg.options['resolution'].should == @options[:resolution]
|
|
45
|
+
ffmpeg.options['input_file'].should == @options[:input_file]
|
|
46
|
+
ffmpeg.options['output_file'].should == @options[:output_file]
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it "should work if options defined as strings, but referenced as symbols" do
|
|
50
|
+
@options.stringify_keys!
|
|
51
|
+
ffmpeg = Ffmpeg.new(@simple_avi, @options)
|
|
52
|
+
ffmpeg.options[:resolution].should == @options['resolution']
|
|
53
|
+
ffmpeg.options[:input_file].should == @options['input_file']
|
|
54
|
+
ffmpeg.options[:output_file].should == @options['output_file']
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it "should ignore extra options (not needed by the recipe)" do
|
|
58
|
+
Ffmpeg.new(@simple_avi, @options.merge(:foo => "bar"))
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# FIXME This won't work here as final_command is not exposed to the testing framework and it will work different on mswin32 if not at all - needs fixing
|
|
62
|
+
#
|
|
63
|
+
#it "should be nice if given :nice => true" do
|
|
64
|
+
# ffmpeg = Ffmpeg.new(@simple_avi, @options.merge(:nice => true))
|
|
65
|
+
# ffmpeg.command.should == "nice ffmpeg -i '#{@options[:input_file]}' -ar 44100 -ab 64 -vcodec xvid -acodec mp3 -r 29.97 -y '#{@options[:output_file]}'"
|
|
66
|
+
#end
|
|
67
|
+
#
|
|
68
|
+
#it "should be nice if given an arbitrary :nice value" do
|
|
69
|
+
# ffmpeg = Ffmpeg.new(@simple_avi, @options.merge(:nice => 12))
|
|
70
|
+
# ffmpeg.command.should == "nice -n12 ffmpeg -i '#{@options[:input_file]}' -ar 44100 -ab 64 -vcodec xvid -acodec mp3 -r 29.97 -y '#{@options[:output_file]}'"
|
|
71
|
+
#end
|
|
72
|
+
|
|
73
|
+
it "should interpolate variables successfully" do
|
|
74
|
+
ffmpeg = Ffmpeg.new(@simple_avi, @options)
|
|
75
|
+
ffmpeg.command.should == "ffmpeg -i '#{@options[:input_file]}' -ar 44100 -ab 64 -vcodec xvid -acodec mp3 -r 29.97 -y '#{@options[:output_file]}'"
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it "the matched_variable method should reference the variable without $" do
|
|
79
|
+
ffmpeg = Ffmpeg.new(@simple_avi, @options)
|
|
80
|
+
ffmpeg.send(:matched_variable, "$input_file$").should == spec_file("kites.mp4")
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
it "the matched_variable method should raise an error when the variable is not found" do
|
|
84
|
+
ffmpeg = Ffmpeg.new(@simple_avi, @options)
|
|
85
|
+
lambda {
|
|
86
|
+
ffmpeg.send(:matched_variable, "$foo$")
|
|
87
|
+
}.should raise_error(TranscoderError::ParameterError)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
it "should raise an exception when a required variable isn't set (1)" do
|
|
91
|
+
lambda {
|
|
92
|
+
ffmpeg = Ffmpeg.new(@simple_avi, {:output_file => "baz"})
|
|
93
|
+
}.should raise_error(TranscoderError::ParameterError)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
it "should raise an error when a recipe includes a variable not supplied (2)" do
|
|
97
|
+
lambda {
|
|
98
|
+
ffmpeg = Ffmpeg.new(@simple_avi + " $novar$", @options)
|
|
99
|
+
}.should raise_error(TranscoderError::ParameterError)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
it "should not raise an error when a variable is supplied but nil" do
|
|
103
|
+
ffmpeg = Ffmpeg.new(@simple_avi, @options.merge(:resolution => nil))
|
|
104
|
+
ffmpeg.command.should == "ffmpeg -i '#{@options[:input_file]}' -ar 44100 -ab 64 -vcodec xvid -acodec mp3 -r 29.97 -y '#{@options[:output_file]}'"
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
it 'should ignore escaped leading \$' do
|
|
108
|
+
ffmpeg = Ffmpeg.new('ffmpeg -i $input_file$ -ar 44100 -ab 64 -fakeoptions \$foo$ -vcodec xvid -acodec mp3 -r 29.97 $resolution$ -y $output_file$', @options)
|
|
109
|
+
ffmpeg.command.should == "ffmpeg -i '#{@options[:input_file]}' -ar 44100 -ab 64 -fakeoptions $foo$ -vcodec xvid -acodec mp3 -r 29.97 #{ffmpeg.resolution} -y '#{@options[:output_file]}'"
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
it 'should ignore escaped trailing \$' do
|
|
113
|
+
ffmpeg = Ffmpeg.new('ffmpeg -i $input_file$ -ar 44100 -ab 64 -fakeoptions $foo\$ -vcodec xvid -acodec mp3 -r 29.97 $resolution$ -y $output_file$', @options)
|
|
114
|
+
ffmpeg.command.should == "ffmpeg -i '#{@options[:input_file]}' -ar 44100 -ab 64 -fakeoptions $foo$ -vcodec xvid -acodec mp3 -r 29.97 #{ffmpeg.resolution} -y '#{@options[:output_file]}'"
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
it 'should ignore two escaped \$' do
|
|
118
|
+
ffmpeg = Ffmpeg.new('ffmpeg -i $input_file$ -ar 44100 -ab 64 -fakeoptions \$foo\$ -vcodec xvid -acodec mp3 -r 29.97 $resolution$ -y $output_file$', @options)
|
|
119
|
+
ffmpeg.command.should == "ffmpeg -i '#{@options[:input_file]}' -ar 44100 -ab 64 -fakeoptions $foo$ -vcodec xvid -acodec mp3 -r 29.97 #{ffmpeg.resolution} -y '#{@options[:output_file]}'"
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
|
2
|
+
|
|
3
|
+
def setup_ffmpeg_spec
|
|
4
|
+
@options = {
|
|
5
|
+
:input_file => spec_file("kites.mp4"),
|
|
6
|
+
:output_file => "bar",
|
|
7
|
+
:width => "320", :height => "240"
|
|
8
|
+
}
|
|
9
|
+
@simple_avi = "ffmpeg -i $input_file$ -ar 44100 -ab 64 -vcodec xvid -acodec libmp3lame -r 29.97 $resolution$ -y $output_file$"
|
|
10
|
+
@ffmpeg = RVideo::Tools::Ffmpeg.new(@simple_avi, @options)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def parsing_result(result_fixture_key)
|
|
14
|
+
lambda { @ffmpeg.send(:parse_result, ffmpeg_result(result_fixture_key)) }
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
module RVideo
|
|
18
|
+
module Tools
|
|
19
|
+
|
|
20
|
+
describe Ffmpeg do
|
|
21
|
+
before do
|
|
22
|
+
setup_ffmpeg_spec
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "should initialize with valid arguments" do
|
|
26
|
+
@ffmpeg.class.should == Ffmpeg
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "should have the correct tool_command" do
|
|
30
|
+
@ffmpeg.tool_command.should == 'ffmpeg'
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "should call parse_result on execute, with a ffmpeg result string" do
|
|
34
|
+
@ffmpeg.should_receive(:parse_result).once.with /\AFFmpeg version/
|
|
35
|
+
@ffmpeg.execute
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "should mixin AbstractTool" do
|
|
39
|
+
Ffmpeg.included_modules.include?(AbstractTool::InstanceMethods).should be_true
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "should set supported options successfully" do
|
|
43
|
+
@ffmpeg.options[:resolution].should == @options[:resolution]
|
|
44
|
+
@ffmpeg.options[:input_file].should == @options[:input_file]
|
|
45
|
+
@ffmpeg.options[:output_file].should == @options[:output_file]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
describe Ffmpeg, " magic variables" do
|
|
51
|
+
before do
|
|
52
|
+
@options = {
|
|
53
|
+
:input_file => spec_file("boat.avi"),
|
|
54
|
+
:output_file => "test"
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
Ffmpeg.video_bit_rate_parameter = Ffmpeg::DEFAULT_VIDEO_BIT_RATE_PARAMETER
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it 'supports copying the originsl :fps' do
|
|
61
|
+
@options.merge! :fps => "copy"
|
|
62
|
+
ffmpeg = Ffmpeg.new("ffmpeg -i $input_file$ -ar 44100 -ab 64 -vcodec xvid -acodec libmp3lame $fps$ -s 320x240 -y $output_file$", @options)
|
|
63
|
+
ffmpeg.command.should == "ffmpeg -i '#{@options[:input_file]}' -ar 44100 -ab 64 -vcodec xvid -acodec libmp3lame -r 15.10 -s 320x240 -y '#{@options[:output_file]}'"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
it 'supports :width and :height options to build :resolution' do
|
|
67
|
+
@options.merge! :width => "640", :height => "360"
|
|
68
|
+
ffmpeg = Ffmpeg.new("ffmpeg -i $input_file$ -ar 44100 -ab 64 -vcodec xvid -acodec libmp3lame -r 29.97 $resolution$ -y $output_file$", @options)
|
|
69
|
+
ffmpeg.command.should == "ffmpeg -i '#{@options[:input_file]}' -ar 44100 -ab 64 -vcodec xvid -acodec libmp3lame -r 29.97 -s 640x360 -y '#{@options[:output_file]}'"
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it 'supports calculated :height' do
|
|
73
|
+
@options.merge! :width => "640"
|
|
74
|
+
ffmpeg = Ffmpeg.new("ffmpeg -i $input_file$ -ar 44100 -ab 64 -vcodec xvid -acodec libmp3lame -r 29.97 $resolution$ -y $output_file$", @options)
|
|
75
|
+
ffmpeg.command.should == "ffmpeg -i '#{@options[:input_file]}' -ar 44100 -ab 64 -vcodec xvid -acodec libmp3lame -r 29.97 -s 640x480 -y '#{@options[:output_file]}'"
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it 'supports calculated :width' do
|
|
79
|
+
@options.merge! :height => "360"
|
|
80
|
+
ffmpeg = Ffmpeg.new("ffmpeg -i $input_file$ -ar 44100 -ab 64 -vcodec xvid -acodec libmp3lame -r 29.97 $resolution$ -y $output_file$", @options)
|
|
81
|
+
ffmpeg.command.should == "ffmpeg -i '#{@options[:input_file]}' -ar 44100 -ab 64 -vcodec xvid -acodec libmp3lame -r 29.97 -s 480x360 -y '#{@options[:output_file]}'"
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
it 'supports :resolution' do
|
|
85
|
+
@options.merge! :resolution => "640x360"
|
|
86
|
+
ffmpeg = Ffmpeg.new("ffmpeg -i $input_file$ -ar 44100 -ab 64 -vcodec xvid -acodec libmp3lame -r 29.97 $resolution$ -y $output_file$", @options)
|
|
87
|
+
ffmpeg.command.should == "ffmpeg -i '#{@options[:input_file]}' -ar 44100 -ab 64 -vcodec xvid -acodec libmp3lame -r 29.97 -s 640x360 -y '#{@options[:output_file]}'"
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
###
|
|
91
|
+
|
|
92
|
+
it 'supports :video_bit_rate' do
|
|
93
|
+
@options.merge! :video_bit_rate => 666
|
|
94
|
+
ffmpeg = Ffmpeg.new("ffmpeg -i $input_file$ $video_bit_rate$ -y $output_file$", @options)
|
|
95
|
+
ffmpeg.command.should == "ffmpeg -i '#{@options[:input_file]}' -b 666k -y '#{@options[:output_file]}'"
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
it "supports :video_bit_rate and configurable command flag" do
|
|
99
|
+
Ffmpeg.video_bit_rate_parameter = "v"
|
|
100
|
+
@options.merge! :video_bit_rate => 666
|
|
101
|
+
ffmpeg = Ffmpeg.new("ffmpeg -i $input_file$ $video_bit_rate$ -y $output_file$", @options)
|
|
102
|
+
ffmpeg.command.should == "ffmpeg -i '#{@options[:input_file]}' -v 666k -y '#{@options[:output_file]}'"
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
###
|
|
106
|
+
|
|
107
|
+
it "supports :video_bit_rate_tolerance" do
|
|
108
|
+
@options.merge! :video_bit_rate_tolerance => 666
|
|
109
|
+
ffmpeg = Ffmpeg.new("ffmpeg -i $input_file$ $video_bit_rate_tolerance$ -y $output_file$", @options)
|
|
110
|
+
ffmpeg.command.should == "ffmpeg -i '#{@options[:input_file]}' -bt 666k -y '#{@options[:output_file]}'"
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
###
|
|
114
|
+
|
|
115
|
+
it "supports :video_bit_rate_max and :video_bit_rate_min" do
|
|
116
|
+
@options.merge! :video_bit_rate => 666, :video_bit_rate_min => 666, :video_bit_rate_max => 666
|
|
117
|
+
ffmpeg = Ffmpeg.new("ffmpeg -i $input_file$ $video_bit_rate$ $video_bit_rate_min$ $video_bit_rate_max$ -y $output_file$", @options)
|
|
118
|
+
ffmpeg.command.should == "ffmpeg -i '#{@options[:input_file]}' -b 666k -minrate 666k -maxrate 666k -y '#{@options[:output_file]}'"
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
it "supports :deinterlace => true" do
|
|
122
|
+
@options.merge! :deinterlace => true
|
|
123
|
+
ffmpeg = Ffmpeg.new("ffmpeg -i $input_file$ $deinterlace$ -y $output_file$", @options)
|
|
124
|
+
ffmpeg.command.should == "ffmpeg -i '#{@options[:input_file]}' -deinterlace -y '#{@options[:output_file]}'"
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
it "handles :deinterlace => false correct" do
|
|
128
|
+
@options.merge! :deinterlace => false
|
|
129
|
+
ffmpeg = Ffmpeg.new("ffmpeg -i $input_file$ $deinterlace$ -y $output_file$", @options)
|
|
130
|
+
ffmpeg.command.should == "ffmpeg -i '#{@options[:input_file]}' -y '#{@options[:output_file]}'"
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
###
|
|
134
|
+
|
|
135
|
+
# TODO for these video quality specs we might want to show that the expected
|
|
136
|
+
# bitrate is calculated based on dimensions and framerate so you can better
|
|
137
|
+
# understand it without going to the source.
|
|
138
|
+
|
|
139
|
+
it "supports :video_quality => 'low'" do
|
|
140
|
+
@options.merge! :video_quality => "low"
|
|
141
|
+
ffmpeg = Ffmpeg.new("ffmpeg -i $input_file$ $video_quality$ -y $output_file$", @options)
|
|
142
|
+
ffmpeg.command.should == "ffmpeg -i '#{@options[:input_file]}' -b 96k -crf 30 -me zero -subq 1 -refs 1 -threads auto -y '#{@options[:output_file]}'"
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
it "supports :video_quality => 'medium'" do
|
|
146
|
+
@options.merge! :video_quality => "medium"
|
|
147
|
+
ffmpeg = Ffmpeg.new("ffmpeg -i $input_file$ $video_quality$ -y $output_file$", @options)
|
|
148
|
+
ffmpeg.command.should == "ffmpeg -i '#{@options[:input_file]}' -b 128k -crf 22 -flags +loop -cmp +sad -partitions +parti4x4+partp8x8+partb8x8 -flags2 +mixed_refs -me hex -subq 3 -trellis 1 -refs 2 -bf 3 -b_strategy 1 -coder 1 -me_range 16 -g 250 -y '#{@options[:output_file]}'"
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
it "supports :video_quality => 'high'" do
|
|
152
|
+
@options.merge! :video_quality => "high"
|
|
153
|
+
ffmpeg = Ffmpeg.new("ffmpeg -i $input_file$ $video_quality$ -y $output_file$", @options)
|
|
154
|
+
ffmpeg.command.should == "ffmpeg -i '#{@options[:input_file]}' -b 322k -crf 18 -flags +loop -cmp +sad -partitions +parti4x4+partp8x8+partb8x8 -flags2 +mixed_refs -me full -subq 6 -trellis 1 -refs 3 -bf 3 -b_strategy 1 -coder 1 -me_range 16 -g 250 -keyint_min 25 -sc_threshold 40 -i_qfactor 0.71 -y '#{@options[:output_file]}'"
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
###
|
|
158
|
+
|
|
159
|
+
it "supports :video_quality => 'low' with arbitrary :video_bit_rate" do
|
|
160
|
+
@options.merge! :video_quality => "low", :video_bit_rate => 666
|
|
161
|
+
ffmpeg = Ffmpeg.new("ffmpeg -i $input_file$ $video_quality$ -y $output_file$", @options)
|
|
162
|
+
ffmpeg.command.should == "ffmpeg -i '#{@options[:input_file]}' -b 666k -crf 30 -me zero -subq 1 -refs 1 -threads auto -y '#{@options[:output_file]}'"
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
it "supports :video_quality => 'medium' with arbitrary :video_bit_rate" do
|
|
166
|
+
@options.merge! :video_quality => "medium", :video_bit_rate => 666
|
|
167
|
+
ffmpeg = Ffmpeg.new("ffmpeg -i $input_file$ $video_quality$ -y $output_file$", @options)
|
|
168
|
+
ffmpeg.command.should == "ffmpeg -i '#{@options[:input_file]}' -b 666k -crf 22 -flags +loop -cmp +sad -partitions +parti4x4+partp8x8+partb8x8 -flags2 +mixed_refs -me hex -subq 3 -trellis 1 -refs 2 -bf 3 -b_strategy 1 -coder 1 -me_range 16 -g 250 -y '#{@options[:output_file]}'"
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
it "supports :video_quality => 'high' with arbitrary :video_bit_rate" do
|
|
172
|
+
@options.merge! :video_quality => "high", :video_bit_rate => 666
|
|
173
|
+
ffmpeg = Ffmpeg.new("ffmpeg -i $input_file$ $video_quality$ -y $output_file$", @options)
|
|
174
|
+
ffmpeg.command.should == "ffmpeg -i '#{@options[:input_file]}' -b 666k -crf 18 -flags +loop -cmp +sad -partitions +parti4x4+partp8x8+partb8x8 -flags2 +mixed_refs -me full -subq 6 -trellis 1 -refs 3 -bf 3 -b_strategy 1 -coder 1 -me_range 16 -g 250 -keyint_min 25 -sc_threshold 40 -i_qfactor 0.71 -y '#{@options[:output_file]}'"
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
it "should support passthrough scaled and rounded height" do
|
|
178
|
+
options = {:input_file => spec_file("kites.mp4"), :output_file => "bar", :width => "640"}
|
|
179
|
+
command = "ffmpeg -i $input_file$ -ar 44100 -ab 64 -vcodec xvid -acodec libmp3lame -r 29.97 $resolution$ -y $output_file$"
|
|
180
|
+
ffmpeg = Ffmpeg.new(command, options)
|
|
181
|
+
ffmpeg.command.should == "ffmpeg -i '#{options[:input_file]}' -ar 44100 -ab 64 -vcodec xvid -acodec libmp3lame -r 29.97 -s 640x528 -y 'bar'"
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
it "should support passthrough scaled and rounded width" do
|
|
185
|
+
options = {:input_file => spec_file("kites.mp4"), :output_file => "bar", :height => "360"}
|
|
186
|
+
command = "ffmpeg -i $input_file$ -ar 44100 -ab 64 -vcodec xvid -acodec libmp3lame -r 29.97 $resolution$ -y $output_file$"
|
|
187
|
+
ffmpeg = Ffmpeg.new(command, options)
|
|
188
|
+
ffmpeg.command.should == "ffmpeg -i '#{options[:input_file]}' -ar 44100 -ab 64 -vcodec xvid -acodec libmp3lame -r 29.97 -s 448x360 -y 'bar'"
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
describe Ffmpeg, " when parsing a result" do
|
|
193
|
+
before do
|
|
194
|
+
setup_ffmpeg_spec
|
|
195
|
+
|
|
196
|
+
@result = ffmpeg_result(:result1)
|
|
197
|
+
@result2 = ffmpeg_result(:result2)
|
|
198
|
+
@result3 = ffmpeg_result(:result3)
|
|
199
|
+
@result4 = ffmpeg_result(:result4)
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
it "should create correct result metadata" do
|
|
203
|
+
@ffmpeg.send(:parse_result, @result).should be_true
|
|
204
|
+
@ffmpeg.frame.should == '4126'
|
|
205
|
+
@ffmpeg.output_fps.should be_nil
|
|
206
|
+
@ffmpeg.q.should == '31.0'
|
|
207
|
+
@ffmpeg.size.should == '5917kB'
|
|
208
|
+
@ffmpeg.time.should == '69.1'
|
|
209
|
+
@ffmpeg.output_bitrate.should == '702.0kbits/s'
|
|
210
|
+
@ffmpeg.video_size.should == "2417kB"
|
|
211
|
+
@ffmpeg.audio_size.should == "540kB"
|
|
212
|
+
@ffmpeg.header_size.should == "0kB"
|
|
213
|
+
@ffmpeg.overhead.should == "100.140277%"
|
|
214
|
+
@ffmpeg.psnr.should be_nil
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
it "should create correct result metadata (2)" do
|
|
218
|
+
@ffmpeg.send(:parse_result, @result2).should be_true
|
|
219
|
+
@ffmpeg.frame.should == '584'
|
|
220
|
+
@ffmpeg.output_fps.should be_nil
|
|
221
|
+
@ffmpeg.q.should == '6.0'
|
|
222
|
+
@ffmpeg.size.should == '708kB'
|
|
223
|
+
@ffmpeg.time.should == '19.5'
|
|
224
|
+
@ffmpeg.output_bitrate.should == '297.8kbits/s'
|
|
225
|
+
@ffmpeg.video_size.should == "49kB"
|
|
226
|
+
@ffmpeg.audio_size.should == "153kB"
|
|
227
|
+
@ffmpeg.header_size.should == "0kB"
|
|
228
|
+
@ffmpeg.overhead.should == "250.444444%"
|
|
229
|
+
@ffmpeg.psnr.should be_nil
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
it "should create correct result metadata (3)" do
|
|
233
|
+
@ffmpeg.send(:parse_result, @result3).should be_true
|
|
234
|
+
@ffmpeg.frame.should == '273'
|
|
235
|
+
@ffmpeg.output_fps.should == "31"
|
|
236
|
+
@ffmpeg.q.should == '10.0'
|
|
237
|
+
@ffmpeg.size.should == '398kB'
|
|
238
|
+
@ffmpeg.time.should == '5.9'
|
|
239
|
+
@ffmpeg.output_bitrate.should == '551.8kbits/s'
|
|
240
|
+
@ffmpeg.video_size.should == "284kB"
|
|
241
|
+
@ffmpeg.audio_size.should == "92kB"
|
|
242
|
+
@ffmpeg.header_size.should == "0kB"
|
|
243
|
+
@ffmpeg.overhead.should == "5.723981%"
|
|
244
|
+
@ffmpeg.psnr.should be_nil
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
it "should create correct result metadata (4)" do
|
|
248
|
+
@ffmpeg.send(:parse_result, @result4).should be_true
|
|
249
|
+
@ffmpeg.frame.should be_nil
|
|
250
|
+
@ffmpeg.output_fps.should be_nil
|
|
251
|
+
@ffmpeg.q.should be_nil
|
|
252
|
+
@ffmpeg.size.should == '1080kB'
|
|
253
|
+
@ffmpeg.time.should == '69.1'
|
|
254
|
+
@ffmpeg.output_bitrate.should == '128.0kbits'
|
|
255
|
+
@ffmpeg.video_size.should == "0kB"
|
|
256
|
+
@ffmpeg.audio_size.should == "1080kB"
|
|
257
|
+
@ffmpeg.header_size.should == "0kB"
|
|
258
|
+
@ffmpeg.overhead.should == "0.002893%"
|
|
259
|
+
@ffmpeg.psnr.should be_nil
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
it "ffmpeg should calculate PSNR if it is turned on" do
|
|
263
|
+
@ffmpeg.send(:parse_result, @result.gsub("Lsize=","LPSNR=Y:33.85 U:37.61 V:37.46 *:34.77 size=")).should be_true
|
|
264
|
+
@ffmpeg.psnr.should == "Y:33.85 U:37.61 V:37.46 *:34.77"
|
|
265
|
+
end
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
context Ffmpeg, "result parsing should raise an exception" do
|
|
269
|
+
before do
|
|
270
|
+
setup_ffmpeg_spec
|
|
271
|
+
@results = load_fixture :ffmpeg_results
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
specify "when a param is missing a value" do
|
|
275
|
+
parsing_result(:param_missing_value).
|
|
276
|
+
should raise_error(TranscoderError::InvalidCommand, /Expected .+ for .+ but found: .+/)
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
specify "when codec not supported" do
|
|
280
|
+
parsing_result(:amr_nb_not_supported).
|
|
281
|
+
should raise_error(TranscoderError::InvalidFile, "Codec amr_nb not supported by this build of ffmpeg")
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
specify "when not passed a command" do
|
|
285
|
+
parsing_result(:missing_command).
|
|
286
|
+
should raise_error(TranscoderError::InvalidCommand, "must pass a command to ffmpeg")
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
specify "when given a broken command" do
|
|
290
|
+
parsing_result(:broken_command).
|
|
291
|
+
should raise_error(TranscoderError::InvalidCommand, "Unable for find a suitable output format for 'foo'")
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
specify "when the output file has no streams" do
|
|
295
|
+
parsing_result(:output_has_no_streams).
|
|
296
|
+
should raise_error(TranscoderError, /Output file does not contain.*stream/)
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
specify "when given a missing input file" do
|
|
300
|
+
parsing_result(:missing_input_file).
|
|
301
|
+
should raise_error(TranscoderError::InvalidFile, /I\/O error: .+/)
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
specify "when given a file it can't handle"
|
|
305
|
+
|
|
306
|
+
specify "when cancelled halfway through"
|
|
307
|
+
|
|
308
|
+
specify "when receiving unexpected results" do
|
|
309
|
+
parsing_result(:unexpected_results).
|
|
310
|
+
should raise_error(TranscoderError::UnexpectedResult, 'foo - bar')
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
specify "with an unsupported codec" do
|
|
314
|
+
@ffmpeg.original = Inspector.new(:raw_response => files('kites2'))
|
|
315
|
+
|
|
316
|
+
parsing_result(:unsupported_codec).
|
|
317
|
+
should raise_error(TranscoderError::InvalidFile, /samr/)
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
specify "when a stream cannot be written" do
|
|
321
|
+
parsing_result(:unwritable_stream).
|
|
322
|
+
should raise_error(TranscoderError, /flv doesnt support.*incorrect codec/)
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
end
|
|
326
|
+
end
|
|
327
|
+
end
|