newbamboo-rvideo 0.9.6

Sign up to get free protection for your applications and to get access to all the features.
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 +68 -0
  6. data/README +106 -0
  7. data/RULES +11 -0
  8. data/Rakefile +63 -0
  9. data/config/boot.rb +25 -0
  10. data/lib/rvideo.rb +46 -0
  11. data/lib/rvideo/errors.rb +24 -0
  12. data/lib/rvideo/float.rb +7 -0
  13. data/lib/rvideo/frame_capturer.rb +127 -0
  14. data/lib/rvideo/inspector.rb +482 -0
  15. data/lib/rvideo/reporter.rb +176 -0
  16. data/lib/rvideo/reporter/views/index.html.erb +27 -0
  17. data/lib/rvideo/reporter/views/report.css +27 -0
  18. data/lib/rvideo/reporter/views/report.html.erb +81 -0
  19. data/lib/rvideo/reporter/views/report.js +9 -0
  20. data/lib/rvideo/string.rb +5 -0
  21. data/lib/rvideo/tools/abstract_tool.rb +406 -0
  22. data/lib/rvideo/tools/ffmpeg.rb +356 -0
  23. data/lib/rvideo/tools/ffmpeg2theora.rb +42 -0
  24. data/lib/rvideo/tools/flvtool2.rb +50 -0
  25. data/lib/rvideo/tools/mencoder.rb +103 -0
  26. data/lib/rvideo/tools/mp4box.rb +21 -0
  27. data/lib/rvideo/tools/mp4creator.rb +35 -0
  28. data/lib/rvideo/tools/mplayer.rb +31 -0
  29. data/lib/rvideo/tools/qtfaststart.rb +37 -0
  30. data/lib/rvideo/tools/segmenter.rb +21 -0
  31. data/lib/rvideo/tools/yamdi.rb +44 -0
  32. data/lib/rvideo/transcoder.rb +139 -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 +111 -0
  54. data/spec/units/ffmpeg_spec.rb +323 -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 +179 -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,111 @@
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
+ it "should interpolate variables successfully" do
62
+ ffmpeg = Ffmpeg.new(@simple_avi, @options)
63
+ ffmpeg.command.should == "ffmpeg -i '#{@options[:input_file]}' -ar 44100 -ab 64 -vcodec xvid -acodec mp3 -r 29.97 -y '#{@options[:output_file]}'"
64
+ end
65
+
66
+ it "the matched_variable method should reference the variable without $" do
67
+ ffmpeg = Ffmpeg.new(@simple_avi, @options)
68
+ ffmpeg.send(:matched_variable, "$input_file$").should == spec_file("kites.mp4")
69
+ end
70
+
71
+ it "the matched_variable method should raise an error when the variable is not found" do
72
+ ffmpeg = Ffmpeg.new(@simple_avi, @options)
73
+ lambda {
74
+ ffmpeg.send(:matched_variable, "$foo$")
75
+ }.should raise_error(TranscoderError::ParameterError)
76
+ end
77
+
78
+ it "should raise an exception when a required variable isn't set (1)" do
79
+ lambda {
80
+ ffmpeg = Ffmpeg.new(@simple_avi, {:output_file => "baz"})
81
+ }.should raise_error(TranscoderError::ParameterError)
82
+ end
83
+
84
+ it "should raise an error when a recipe includes a variable not supplied (2)" do
85
+ lambda {
86
+ ffmpeg = Ffmpeg.new(@simple_avi + " $novar$", @options)
87
+ }.should raise_error(TranscoderError::ParameterError)
88
+ end
89
+
90
+ it "should not raise an error when a variable is supplied but nil" do
91
+ ffmpeg = Ffmpeg.new(@simple_avi, @options.merge(:resolution => nil))
92
+ ffmpeg.command.should == "ffmpeg -i '#{@options[:input_file]}' -ar 44100 -ab 64 -vcodec xvid -acodec mp3 -r 29.97 -y '#{@options[:output_file]}'"
93
+ end
94
+
95
+ it 'should ignore escaped leading \$' do
96
+ 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)
97
+ 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]}'"
98
+ end
99
+
100
+ it 'should ignore escaped trailing \$' do
101
+ 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)
102
+ 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]}'"
103
+ end
104
+
105
+ it 'should ignore two escaped \$' do
106
+ 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)
107
+ 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]}'"
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,323 @@
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
+ ###
85
+
86
+ it 'supports :video_bit_rate' do
87
+ @options.merge! :video_bit_rate => 666
88
+ ffmpeg = Ffmpeg.new("ffmpeg -i $input_file$ $video_bit_rate$ -y $output_file$", @options)
89
+ ffmpeg.command.should == "ffmpeg -i '#{@options[:input_file]}' -b 666k -y '#{@options[:output_file]}'"
90
+ end
91
+
92
+ it "supports :video_bit_rate and configurable command flag" do
93
+ Ffmpeg.video_bit_rate_parameter = "v"
94
+ @options.merge! :video_bit_rate => 666
95
+ ffmpeg = Ffmpeg.new("ffmpeg -i $input_file$ $video_bit_rate$ -y $output_file$", @options)
96
+ ffmpeg.command.should == "ffmpeg -i '#{@options[:input_file]}' -v 666k -y '#{@options[:output_file]}'"
97
+ end
98
+
99
+ ###
100
+
101
+ it "supports :video_bit_rate_tolerance" do
102
+ @options.merge! :video_bit_rate_tolerance => 666
103
+ ffmpeg = Ffmpeg.new("ffmpeg -i $input_file$ $video_bit_rate_tolerance$ -y $output_file$", @options)
104
+ ffmpeg.command.should == "ffmpeg -i '#{@options[:input_file]}' -bt 666k -y '#{@options[:output_file]}'"
105
+ end
106
+
107
+ ###
108
+
109
+ it "supports :video_bit_rate_max and :video_bit_rate_min" do
110
+ @options.merge! :video_bit_rate => 666, :video_bit_rate_min => 666, :video_bit_rate_max => 666
111
+ ffmpeg = Ffmpeg.new("ffmpeg -i $input_file$ $video_bit_rate$ $video_bit_rate_min$ $video_bit_rate_max$ -y $output_file$", @options)
112
+ ffmpeg.command.should == "ffmpeg -i '#{@options[:input_file]}' -b 666k -minrate 666k -maxrate 666k -y '#{@options[:output_file]}'"
113
+ end
114
+
115
+ it "supports :deinterlace => true" do
116
+ @options.merge! :deinterlace => true
117
+ ffmpeg = Ffmpeg.new("ffmpeg -i $input_file$ $deinterlace$ -y $output_file$", @options)
118
+ ffmpeg.command.should == "ffmpeg -i '#{@options[:input_file]}' -deinterlace -y '#{@options[:output_file]}'"
119
+ end
120
+
121
+ it "handles :deinterlace => false correct" do
122
+ @options.merge! :deinterlace => false
123
+ ffmpeg = Ffmpeg.new("ffmpeg -i $input_file$ $deinterlace$ -y $output_file$", @options)
124
+ ffmpeg.command.should == "ffmpeg -i '#{@options[:input_file]}' -y '#{@options[:output_file]}'"
125
+ end
126
+
127
+ ###
128
+
129
+ # TODO for these video quality specs we might want to show that the expected
130
+ # bitrate is calculated based on dimensions and framerate so you can better
131
+ # understand it without going to the source.
132
+
133
+ it "supports :video_quality => 'low'" do
134
+ @options.merge! :video_quality => "low"
135
+ ffmpeg = Ffmpeg.new("ffmpeg -i $input_file$ $video_quality$ -y $output_file$", @options)
136
+ ffmpeg.command.should == "ffmpeg -i '#{@options[:input_file]}' -b 96k -crf 30 -me zero -subq 1 -refs 1 -threads auto -y '#{@options[:output_file]}'"
137
+ end
138
+
139
+ it "supports :video_quality => 'medium'" do
140
+ @options.merge! :video_quality => "medium"
141
+ ffmpeg = Ffmpeg.new("ffmpeg -i $input_file$ $video_quality$ -y $output_file$", @options)
142
+ 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]}'"
143
+ end
144
+
145
+ it "supports :video_quality => 'high'" do
146
+ @options.merge! :video_quality => "high"
147
+ ffmpeg = Ffmpeg.new("ffmpeg -i $input_file$ $video_quality$ -y $output_file$", @options)
148
+ 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]}'"
149
+ end
150
+
151
+ ###
152
+
153
+ it "supports :video_quality => 'low' with arbitrary :video_bit_rate" do
154
+ @options.merge! :video_quality => "low", :video_bit_rate => 666
155
+ ffmpeg = Ffmpeg.new("ffmpeg -i $input_file$ $video_quality$ -y $output_file$", @options)
156
+ ffmpeg.command.should == "ffmpeg -i '#{@options[:input_file]}' -b 666k -crf 30 -me zero -subq 1 -refs 1 -threads auto -y '#{@options[:output_file]}'"
157
+ end
158
+
159
+ it "supports :video_quality => 'medium' with arbitrary :video_bit_rate" do
160
+ @options.merge! :video_quality => "medium", :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 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]}'"
163
+ end
164
+
165
+ it "supports :video_quality => 'high' with arbitrary :video_bit_rate" do
166
+ @options.merge! :video_quality => "high", :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 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]}'"
169
+ end
170
+
171
+ # These appear unsupported..
172
+ #
173
+ # it 'should support passthrough height' do
174
+ # options = {:input_file => spec_file("kites.mp4"), :output_file => "bar", :width => "640"}
175
+ # command = "ffmpeg -i $input_file$ -ar 44100 -ab 64 -vcodec xvid -acodec libmp3lame -r 29.97 $resolution$ -y $output_file$"
176
+ # ffmpeg = Ffmpeg.new(command, options)
177
+ # ffmpeg.command.should == "ffmpeg -i '#{options[:input_file]}' -ar 44100 -ab 64 -vcodec xvid -acodec libmp3lame -r 29.97 -s 640x720 -y 'bar'"
178
+ # end
179
+ #
180
+ # it 'should support passthrough width' do
181
+ # options = {:input_file => spec_file("kites.mp4"), :output_file => "bar", :height => "360"}
182
+ # command = "ffmpeg -i $input_file$ -ar 44100 -ab 64 -vcodec xvid -acodec libmp3lame -r 29.97 $resolution$ -y $output_file$"
183
+ # ffmpeg = Ffmpeg.new(command, options)
184
+ # ffmpeg.command.should == "ffmpeg -i '#{options[:input_file]}' -ar 44100 -ab 64 -vcodec xvid -acodec libmp3lame -r 29.97 -s 1280x360 -y 'bar'"
185
+ # end
186
+ end
187
+
188
+ describe Ffmpeg, " when parsing a result" do
189
+ before do
190
+ setup_ffmpeg_spec
191
+
192
+ @result = ffmpeg_result(:result1)
193
+ @result2 = ffmpeg_result(:result2)
194
+ @result3 = ffmpeg_result(:result3)
195
+ @result4 = ffmpeg_result(:result4)
196
+ end
197
+
198
+ it "should create correct result metadata" do
199
+ @ffmpeg.send(:parse_result, @result).should be_true
200
+ @ffmpeg.frame.should == '4126'
201
+ @ffmpeg.output_fps.should be_nil
202
+ @ffmpeg.q.should == '31.0'
203
+ @ffmpeg.size.should == '5917kB'
204
+ @ffmpeg.time.should == '69.1'
205
+ @ffmpeg.output_bitrate.should == '702.0kbits/s'
206
+ @ffmpeg.video_size.should == "2417kB"
207
+ @ffmpeg.audio_size.should == "540kB"
208
+ @ffmpeg.header_size.should == "0kB"
209
+ @ffmpeg.overhead.should == "100.140277%"
210
+ @ffmpeg.psnr.should be_nil
211
+ end
212
+
213
+ it "should create correct result metadata (2)" do
214
+ @ffmpeg.send(:parse_result, @result2).should be_true
215
+ @ffmpeg.frame.should == '584'
216
+ @ffmpeg.output_fps.should be_nil
217
+ @ffmpeg.q.should == '6.0'
218
+ @ffmpeg.size.should == '708kB'
219
+ @ffmpeg.time.should == '19.5'
220
+ @ffmpeg.output_bitrate.should == '297.8kbits/s'
221
+ @ffmpeg.video_size.should == "49kB"
222
+ @ffmpeg.audio_size.should == "153kB"
223
+ @ffmpeg.header_size.should == "0kB"
224
+ @ffmpeg.overhead.should == "250.444444%"
225
+ @ffmpeg.psnr.should be_nil
226
+ end
227
+
228
+ it "should create correct result metadata (3)" do
229
+ @ffmpeg.send(:parse_result, @result3).should be_true
230
+ @ffmpeg.frame.should == '273'
231
+ @ffmpeg.output_fps.should == "31"
232
+ @ffmpeg.q.should == '10.0'
233
+ @ffmpeg.size.should == '398kB'
234
+ @ffmpeg.time.should == '5.9'
235
+ @ffmpeg.output_bitrate.should == '551.8kbits/s'
236
+ @ffmpeg.video_size.should == "284kB"
237
+ @ffmpeg.audio_size.should == "92kB"
238
+ @ffmpeg.header_size.should == "0kB"
239
+ @ffmpeg.overhead.should == "5.723981%"
240
+ @ffmpeg.psnr.should be_nil
241
+ end
242
+
243
+ it "should create correct result metadata (4)" do
244
+ @ffmpeg.send(:parse_result, @result4).should be_true
245
+ @ffmpeg.frame.should be_nil
246
+ @ffmpeg.output_fps.should be_nil
247
+ @ffmpeg.q.should be_nil
248
+ @ffmpeg.size.should == '1080kB'
249
+ @ffmpeg.time.should == '69.1'
250
+ @ffmpeg.output_bitrate.should == '128.0kbits'
251
+ @ffmpeg.video_size.should == "0kB"
252
+ @ffmpeg.audio_size.should == "1080kB"
253
+ @ffmpeg.header_size.should == "0kB"
254
+ @ffmpeg.overhead.should == "0.002893%"
255
+ @ffmpeg.psnr.should be_nil
256
+ end
257
+
258
+ it "ffmpeg should calculate PSNR if it is turned on" do
259
+ @ffmpeg.send(:parse_result, @result.gsub("Lsize=","LPSNR=Y:33.85 U:37.61 V:37.46 *:34.77 size=")).should be_true
260
+ @ffmpeg.psnr.should == "Y:33.85 U:37.61 V:37.46 *:34.77"
261
+ end
262
+ end
263
+
264
+ context Ffmpeg, "result parsing should raise an exception" do
265
+ setup do
266
+ setup_ffmpeg_spec
267
+ @results = load_fixture :ffmpeg_results
268
+ end
269
+
270
+ specify "when a param is missing a value" do
271
+ parsing_result(:param_missing_value).
272
+ should raise_error(TranscoderError::InvalidCommand, /Expected .+ for .+ but found: .+/)
273
+ end
274
+
275
+ specify "when codec not supported" do
276
+ parsing_result(:amr_nb_not_supported).
277
+ should raise_error(TranscoderError::InvalidFile, "Codec amr_nb not supported by this build of ffmpeg")
278
+ end
279
+
280
+ specify "when not passed a command" do
281
+ parsing_result(:missing_command).
282
+ should raise_error(TranscoderError::InvalidCommand, "must pass a command to ffmpeg")
283
+ end
284
+
285
+ specify "when given a broken command" do
286
+ parsing_result(:broken_command).
287
+ should raise_error(TranscoderError::InvalidCommand, "Unable for find a suitable output format for 'foo'")
288
+ end
289
+
290
+ specify "when the output file has no streams" do
291
+ parsing_result(:output_has_no_streams).
292
+ should raise_error(TranscoderError, /Output file does not contain.*stream/)
293
+ end
294
+
295
+ specify "when given a missing input file" do
296
+ parsing_result(:missing_input_file).
297
+ should raise_error(TranscoderError::InvalidFile, /I\/O error: .+/)
298
+ end
299
+
300
+ specify "when given a file it can't handle"
301
+
302
+ specify "when cancelled halfway through"
303
+
304
+ specify "when receiving unexpected results" do
305
+ parsing_result(:unexpected_results).
306
+ should raise_error(TranscoderError::UnexpectedResult, 'foo - bar')
307
+ end
308
+
309
+ specify "with an unsupported codec" do
310
+ @ffmpeg.original = Inspector.new(:raw_response => files('kites2'))
311
+
312
+ parsing_result(:unsupported_codec).
313
+ should raise_error(TranscoderError::InvalidFile, /samr/)
314
+ end
315
+
316
+ specify "when a stream cannot be written" do
317
+ parsing_result(:unwritable_stream).
318
+ should raise_error(TranscoderError, /flv doesnt support.*incorrect codec/)
319
+ end
320
+
321
+ end
322
+ end
323
+ end