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.
Files changed (69) hide show
  1. data/CHANGELOG +70 -0
  2. data/ENV +100 -0
  3. data/ENV2 +129 -0
  4. data/LICENSE +20 -0
  5. data/Manifest +67 -0
  6. data/README +91 -0
  7. data/RULES +11 -0
  8. data/Rakefile +63 -0
  9. data/axtro-rvideo.gemspec +36 -0
  10. data/config/boot.rb +25 -0
  11. data/lib/rvideo.rb +44 -0
  12. data/lib/rvideo/errors.rb +24 -0
  13. data/lib/rvideo/float.rb +7 -0
  14. data/lib/rvideo/frame_capturer.rb +129 -0
  15. data/lib/rvideo/inspector.rb +483 -0
  16. data/lib/rvideo/reporter.rb +176 -0
  17. data/lib/rvideo/reporter/views/index.html.erb +27 -0
  18. data/lib/rvideo/reporter/views/report.css +27 -0
  19. data/lib/rvideo/reporter/views/report.html.erb +81 -0
  20. data/lib/rvideo/reporter/views/report.js +9 -0
  21. data/lib/rvideo/string.rb +5 -0
  22. data/lib/rvideo/tools/abstract_tool.rb +414 -0
  23. data/lib/rvideo/tools/ffmpeg.rb +286 -0
  24. data/lib/rvideo/tools/ffmpeg2theora.rb +42 -0
  25. data/lib/rvideo/tools/flvtool2.rb +50 -0
  26. data/lib/rvideo/tools/mencoder.rb +103 -0
  27. data/lib/rvideo/tools/mp4box.rb +21 -0
  28. data/lib/rvideo/tools/mp4creator.rb +35 -0
  29. data/lib/rvideo/tools/mplayer.rb +31 -0
  30. data/lib/rvideo/tools/qtfaststart.rb +37 -0
  31. data/lib/rvideo/tools/yamdi.rb +44 -0
  32. data/lib/rvideo/transcoder.rb +120 -0
  33. data/lib/rvideo/version.rb +9 -0
  34. data/rvideo.gemspec +36 -0
  35. data/scripts/txt2html +67 -0
  36. data/setup.rb +1585 -0
  37. data/spec/files/boat.avi +0 -0
  38. data/spec/files/kites.mp4 +0 -0
  39. data/spec/fixtures/ffmpeg_builds.yml +28 -0
  40. data/spec/fixtures/ffmpeg_results.yml +608 -0
  41. data/spec/fixtures/files.yml +398 -0
  42. data/spec/fixtures/recipes.yml +58 -0
  43. data/spec/integrations/formats_spec.rb +315 -0
  44. data/spec/integrations/frame_capturer_spec.rb +26 -0
  45. data/spec/integrations/inspection_spec.rb +112 -0
  46. data/spec/integrations/recipes_spec.rb +0 -0
  47. data/spec/integrations/rvideo_spec.rb +17 -0
  48. data/spec/integrations/transcoder_integration_spec.rb +29 -0
  49. data/spec/integrations/transcoding_spec.rb +9 -0
  50. data/spec/spec.opts +1 -0
  51. data/spec/spec_helper.rb +16 -0
  52. data/spec/support.rb +36 -0
  53. data/spec/units/abstract_tool_spec.rb +123 -0
  54. data/spec/units/ffmpeg_spec.rb +327 -0
  55. data/spec/units/flvtool2_spec.rb +324 -0
  56. data/spec/units/frame_capturer_spec.rb +72 -0
  57. data/spec/units/inspector_spec.rb +59 -0
  58. data/spec/units/mencoder_spec.rb +4994 -0
  59. data/spec/units/mp4box_spec.rb +34 -0
  60. data/spec/units/mp4creator_spec.rb +34 -0
  61. data/spec/units/mplayer_spec.rb +34 -0
  62. data/spec/units/qtfaststart_spec.rb +35 -0
  63. data/spec/units/string_spec.rb +8 -0
  64. data/spec/units/transcoder_spec.rb +156 -0
  65. data/tasks/deployment.rake +5 -0
  66. data/tasks/testing.rake +27 -0
  67. data/tasks/transcoding.rake +40 -0
  68. data/tasks/website.rake +8 -0
  69. 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
@@ -0,0 +1,9 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+
3
+ module RVideo
4
+ describe RVideo do
5
+ before do
6
+
7
+ end
8
+ end
9
+ end
@@ -0,0 +1 @@
1
+ --color
@@ -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
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
@@ -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