twinge-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 (68) 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/config/boot.rb +25 -0
  10. data/lib/rvideo.rb +44 -0
  11. data/lib/rvideo/errors.rb +24 -0
  12. data/lib/rvideo/float.rb +7 -0
  13. data/lib/rvideo/frame_capturer.rb +126 -0
  14. data/lib/rvideo/inspector.rb +481 -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 +401 -0
  22. data/lib/rvideo/tools/ffmpeg.rb +277 -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/yamdi.rb +44 -0
  31. data/lib/rvideo/transcoder.rb +120 -0
  32. data/lib/rvideo/version.rb +9 -0
  33. data/rvideo.gemspec +37 -0
  34. data/scripts/txt2html +67 -0
  35. data/setup.rb +1585 -0
  36. data/spec/files/boat.avi +0 -0
  37. data/spec/files/kites.mp4 +0 -0
  38. data/spec/fixtures/ffmpeg_builds.yml +28 -0
  39. data/spec/fixtures/ffmpeg_results.yml +608 -0
  40. data/spec/fixtures/files.yml +398 -0
  41. data/spec/fixtures/recipes.yml +58 -0
  42. data/spec/integrations/formats_spec.rb +315 -0
  43. data/spec/integrations/frame_capturer_spec.rb +26 -0
  44. data/spec/integrations/inspection_spec.rb +112 -0
  45. data/spec/integrations/recipes_spec.rb +0 -0
  46. data/spec/integrations/rvideo_spec.rb +17 -0
  47. data/spec/integrations/transcoder_integration_spec.rb +29 -0
  48. data/spec/integrations/transcoding_spec.rb +9 -0
  49. data/spec/spec.opts +1 -0
  50. data/spec/spec_helper.rb +16 -0
  51. data/spec/support.rb +36 -0
  52. data/spec/units/abstract_tool_spec.rb +111 -0
  53. data/spec/units/ffmpeg_spec.rb +323 -0
  54. data/spec/units/flvtool2_spec.rb +324 -0
  55. data/spec/units/frame_capturer_spec.rb +72 -0
  56. data/spec/units/inspector_spec.rb +59 -0
  57. data/spec/units/mencoder_spec.rb +4994 -0
  58. data/spec/units/mp4box_spec.rb +34 -0
  59. data/spec/units/mp4creator_spec.rb +34 -0
  60. data/spec/units/mplayer_spec.rb +34 -0
  61. data/spec/units/qtfaststart_spec.rb +35 -0
  62. data/spec/units/string_spec.rb +8 -0
  63. data/spec/units/transcoder_spec.rb +156 -0
  64. data/tasks/deployment.rake +5 -0
  65. data/tasks/testing.rake +27 -0
  66. data/tasks/transcoding.rake +40 -0
  67. data/tasks/website.rake +8 -0
  68. metadata +175 -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
data/spec/spec.opts ADDED
@@ -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
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
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,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