bulldog 0.0.1

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 (77) hide show
  1. data/.gitignore +2 -0
  2. data/DESCRIPTION.txt +3 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +18 -0
  5. data/Rakefile +64 -0
  6. data/VERSION +1 -0
  7. data/bulldog.gemspec +157 -0
  8. data/lib/bulldog.rb +95 -0
  9. data/lib/bulldog/attachment.rb +49 -0
  10. data/lib/bulldog/attachment/base.rb +167 -0
  11. data/lib/bulldog/attachment/has_dimensions.rb +94 -0
  12. data/lib/bulldog/attachment/image.rb +63 -0
  13. data/lib/bulldog/attachment/maybe.rb +229 -0
  14. data/lib/bulldog/attachment/none.rb +37 -0
  15. data/lib/bulldog/attachment/pdf.rb +63 -0
  16. data/lib/bulldog/attachment/unknown.rb +11 -0
  17. data/lib/bulldog/attachment/video.rb +143 -0
  18. data/lib/bulldog/error.rb +5 -0
  19. data/lib/bulldog/has_attachment.rb +214 -0
  20. data/lib/bulldog/interpolation.rb +73 -0
  21. data/lib/bulldog/missing_file.rb +12 -0
  22. data/lib/bulldog/processor.rb +5 -0
  23. data/lib/bulldog/processor/argument_tree.rb +116 -0
  24. data/lib/bulldog/processor/base.rb +124 -0
  25. data/lib/bulldog/processor/ffmpeg.rb +172 -0
  26. data/lib/bulldog/processor/image_magick.rb +134 -0
  27. data/lib/bulldog/processor/one_shot.rb +19 -0
  28. data/lib/bulldog/reflection.rb +234 -0
  29. data/lib/bulldog/saved_file.rb +19 -0
  30. data/lib/bulldog/stream.rb +186 -0
  31. data/lib/bulldog/style.rb +38 -0
  32. data/lib/bulldog/style_set.rb +101 -0
  33. data/lib/bulldog/tempfile.rb +28 -0
  34. data/lib/bulldog/util.rb +92 -0
  35. data/lib/bulldog/validations.rb +68 -0
  36. data/lib/bulldog/vector2.rb +18 -0
  37. data/rails/init.rb +9 -0
  38. data/script/console +8 -0
  39. data/spec/data/empty.txt +0 -0
  40. data/spec/data/test.jpg +0 -0
  41. data/spec/data/test.mov +0 -0
  42. data/spec/data/test.pdf +0 -0
  43. data/spec/data/test.png +0 -0
  44. data/spec/data/test2.jpg +0 -0
  45. data/spec/helpers/image_creation.rb +8 -0
  46. data/spec/helpers/temporary_directory.rb +25 -0
  47. data/spec/helpers/temporary_models.rb +76 -0
  48. data/spec/helpers/temporary_values.rb +102 -0
  49. data/spec/helpers/test_upload_files.rb +108 -0
  50. data/spec/helpers/time_travel.rb +20 -0
  51. data/spec/integration/data/test.jpg +0 -0
  52. data/spec/integration/lifecycle_hooks_spec.rb +213 -0
  53. data/spec/integration/processing_image_attachments.rb +72 -0
  54. data/spec/integration/processing_video_attachments_spec.rb +82 -0
  55. data/spec/integration/saving_an_attachment_spec.rb +31 -0
  56. data/spec/matchers/file_operations.rb +159 -0
  57. data/spec/spec_helper.rb +76 -0
  58. data/spec/unit/attachment/base_spec.rb +311 -0
  59. data/spec/unit/attachment/image_spec.rb +128 -0
  60. data/spec/unit/attachment/maybe_spec.rb +126 -0
  61. data/spec/unit/attachment/pdf_spec.rb +137 -0
  62. data/spec/unit/attachment/video_spec.rb +176 -0
  63. data/spec/unit/attachment_spec.rb +61 -0
  64. data/spec/unit/has_attachment_spec.rb +700 -0
  65. data/spec/unit/interpolation_spec.rb +108 -0
  66. data/spec/unit/processor/argument_tree_spec.rb +159 -0
  67. data/spec/unit/processor/ffmpeg_spec.rb +467 -0
  68. data/spec/unit/processor/image_magick_spec.rb +260 -0
  69. data/spec/unit/processor/one_shot_spec.rb +70 -0
  70. data/spec/unit/reflection_spec.rb +338 -0
  71. data/spec/unit/stream_spec.rb +234 -0
  72. data/spec/unit/style_set_spec.rb +44 -0
  73. data/spec/unit/style_spec.rb +51 -0
  74. data/spec/unit/validations_spec.rb +491 -0
  75. data/spec/unit/vector2_spec.rb +27 -0
  76. data/tasks/bulldog_tasks.rake +4 -0
  77. metadata +193 -0
@@ -0,0 +1,108 @@
1
+ require 'spec_helper'
2
+
3
+ describe Interpolation do
4
+ use_model_class(:Thing, :photo_file_name => :string)
5
+
6
+ def interpolate(template)
7
+ Interpolation.interpolate(template, @thing, :photo, @style)
8
+ end
9
+
10
+ describe ".to_interpolate" do
11
+ it "should define a custom interpolation token" do
12
+ begin
13
+ Interpolation.to_interpolate(:custom){'VALUE'}
14
+ Thing.has_attachment :attachment do
15
+ style :output
16
+ path "dir/:custom.ext"
17
+ end
18
+ thing = Thing.new
19
+ thing.attachment.interpolate_path(:output).should == "dir/VALUE.ext"
20
+ ensure
21
+ Interpolation.reset
22
+ end
23
+ end
24
+ end
25
+
26
+ describe ".reset" do
27
+ it "should remove custom interpolations" do
28
+ Bulldog.to_interpolate(:custom){'VALUE'}
29
+ Bulldog::Interpolation.reset
30
+ Thing.has_attachment :attachment do
31
+ style :output
32
+ path "dir/:custom.ext"
33
+ end
34
+ thing = Thing.new
35
+ lambda{thing.attachment.interpolate_path(:output)}.should raise_error(Interpolation::Error)
36
+ end
37
+ end
38
+
39
+ describe "when the file name is not being stored" do
40
+ before do
41
+ Thing.has_attachment :photo do
42
+ style :small, {}
43
+ store_attributes :file_name => nil
44
+ end
45
+ @thing = Thing.new(:photo => test_image_file('test.jpg'))
46
+ @style = Thing.attachment_reflections[:photo].styles[:small]
47
+ end
48
+
49
+ it "should interpolate :class as the plural class name" do
50
+ interpolate("a/:class/b").should == "a/things/b"
51
+ end
52
+
53
+ it "should interpolate :id as the record ID" do
54
+ @thing.stubs(:id).returns(123)
55
+ interpolate("a/:id/b").should == "a/123/b"
56
+ end
57
+
58
+ it "should interpolate :id_partition as the record ID split into 3 3-digit partitions, 0-padded" do
59
+ @thing.stubs(:id).returns(12345)
60
+ interpolate("a/:id_partition/b").should == "a/000/012/345/b"
61
+ end
62
+
63
+ it "should interpolate :attachment as the attachment name" do
64
+ interpolate("a/:attachment/b").should == "a/photo/b"
65
+ end
66
+
67
+ it "should interpolate :style as the style name" do
68
+ interpolate("a/:style/b").should == "a/small/b"
69
+ end
70
+
71
+ it "should raise an error for :basename" do
72
+ lambda{interpolate("a/:basename/b")}.should raise_error(Interpolation::Error)
73
+ end
74
+
75
+ it "should raise an error for :extension" do
76
+ lambda{interpolate("a/:extension/b")}.should raise_error(Interpolation::Error)
77
+ end
78
+
79
+ it "should allow using braces for interpolating between symbol characters" do
80
+ @thing.stubs(:id).returns(5)
81
+ interpolate("a/x:{id}x/b").should == "a/x5x/b"
82
+ end
83
+
84
+ it "should raise an error for an unrecognized interpolation key" do
85
+ lambda{interpolate(":invalid")}.should raise_error(Interpolation::Error)
86
+ end
87
+ end
88
+
89
+ describe "when the file name is being stored" do
90
+ before do
91
+ Thing.has_attachment :photo do
92
+ style :small, {}
93
+ store_attributes :file_name => :photo_file_name
94
+ end
95
+
96
+ @thing = Thing.new(:photo => test_image_file('test.jpg'))
97
+ @style = Thing.attachment_reflections[:photo].styles[:small]
98
+ end
99
+
100
+ it "should interpolate :basename as the basename of the uploaded file" do
101
+ interpolate("a/:basename/b").should == "a/test.jpg/b"
102
+ end
103
+
104
+ it "should interpolate :extension as the extension of the uploaded file" do
105
+ interpolate("a/:extension/b").should == "a/jpg/b"
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,159 @@
1
+ require 'spec_helper'
2
+
3
+ describe Processor::ArgumentTree do
4
+ Tree = Processor::ArgumentTree
5
+ Node = Processor::ArgumentTree::Node
6
+
7
+ before do
8
+ @a = Style.new(:a)
9
+ @b = Style.new(:b)
10
+ end
11
+
12
+ describe "initially" do
13
+ before do
14
+ @tree = Tree.new(StyleSet[@a, @b])
15
+ end
16
+
17
+ it "should have only the root node" do
18
+ @tree.root.should be_a(Tree::Node)
19
+ @tree.root.children.should be_empty
20
+ end
21
+
22
+ it "should have all heads pointing to the root node" do
23
+ root = @tree.root
24
+ [@a, @b].map{|style| @tree.heads[style]}.should == [root, root]
25
+ end
26
+ end
27
+
28
+ describe "#add" do
29
+ describe "when the tree is empty" do
30
+ before do
31
+ @tree = Tree.new(StyleSet[@a, @b])
32
+ end
33
+
34
+ it "should create a new node for the given style and arguments" do
35
+ @tree.add(@a, ['a', 'b'])
36
+ @tree.root.children.should have(1).nodes
37
+ @tree.root.children.first.styles.should == [@a]
38
+ @tree.root.children.first.arguments.should == ['a', 'b']
39
+ end
40
+ end
41
+
42
+ describe "when there is a node under the head for the given arguments" do
43
+ before do
44
+ #
45
+ # root --- one --- two
46
+ # ^ ^
47
+ # a b
48
+ #
49
+ @tree = Tree.new(StyleSet[@a])
50
+ @one = Node.new([@a, @b], ['one', '1'])
51
+ @two = Node.new([@a], ['two', '2'])
52
+ @tree.root.children << @one
53
+ @one.children << @two
54
+ @tree.heads[@a] = @two
55
+ @tree.heads[@b] = @one
56
+ end
57
+
58
+ it "should advance the head to that node" do
59
+ @tree.add(@b, ['two', '2'])
60
+ @tree.heads[@b].should equal(@two)
61
+ end
62
+
63
+ it "should add the style to the new head node" do
64
+ @tree.add(@b, ['two', '2'])
65
+ @tree.heads[@b].should equal(@two)
66
+ end
67
+ end
68
+
69
+ describe "when there is no node under the head for the given arguments" do
70
+ before do
71
+ #
72
+ # root --- one
73
+ # ^
74
+ # a,b
75
+ #
76
+ @tree = Tree.new(StyleSet[@a])
77
+ one = Node.new([@a, @b], ['one', '1'])
78
+ @tree.root.children << one
79
+ @tree.heads[@a] = one
80
+ @tree.heads[@b] = one
81
+ end
82
+
83
+ it "should create a new child node and advance the head to it" do
84
+ old_head = @tree.heads[@a]
85
+ @tree.add(@a, ['two', '2'])
86
+ @tree.heads[@a].should == old_head.children.first
87
+ end
88
+
89
+ it "should set the arguments of the new node to the given arguments" do
90
+ @tree.add(@a, ['two', '2'])
91
+ @tree.heads[@a].arguments.should == ['two', '2']
92
+ end
93
+
94
+ it "should add the style to the new head node" do
95
+ @tree.add(@a, ['two', '2'])
96
+ @tree.heads[@a].styles.should == [@a]
97
+ end
98
+ end
99
+ end
100
+
101
+ describe "#arguments" do
102
+ describe "for a nonbranching tree" do
103
+ it "should return just the output file if there are no operations to perform" do
104
+ tree = Tree.new(StyleSet[@a])
105
+ tree.output(@a, 'A.jpg')
106
+ tree.arguments.should == ['A.jpg']
107
+ end
108
+
109
+ it "should return the operator arguments strung together with the output file at the end" do
110
+ tree = Tree.new(StyleSet[@a])
111
+ tree.add(@a, ['-flip'])
112
+ tree.add(@a, ['-flop'])
113
+ tree.output(@a, 'A.jpg')
114
+ tree.arguments.should == ['-flip', '-flop', 'A.jpg']
115
+ end
116
+
117
+ it "should use a -write argument for all but the last output file" do
118
+ tree = Tree.new(StyleSet[@a, @b])
119
+ tree.add(@a, ['-flip'])
120
+ tree.add(@b, ['-flip'])
121
+ tree.output(@a, 'A.jpg')
122
+ tree.output(@b, 'B.jpg')
123
+ tree.arguments.should == ['-flip', '-write', 'A.jpg', 'B.jpg']
124
+ end
125
+ end
126
+
127
+ describe "for a branching tree" do
128
+ it "should clone all but the last level" do
129
+ tree = Tree.new(StyleSet[@a, @b])
130
+ tree.add(@a, ['-auto-orient'])
131
+ tree.add(@b, ['-auto-orient'])
132
+ tree.add(@a, ['-flip'])
133
+ tree.add(@b, ['-flop'])
134
+ tree.output(@a, 'A.jpg')
135
+ tree.output(@b, 'B.jpg')
136
+ tree.arguments.should == ['-auto-orient', '(', '+clone', '-flip', '-write', 'A.jpg', '+delete', ')', '-flop', 'B.jpg']
137
+ end
138
+ end
139
+ end
140
+
141
+ describe "#each_callback" do
142
+ it "should yield callbacks, along with the styles they apply to, in the order they appear in the tree" do
143
+ #
144
+ # * one (1)
145
+ # * two (2) [:a]
146
+ # * three
147
+ # * four (4) [:b]
148
+ #
149
+ tokens = []
150
+ tree = Tree.new(StyleSet[@a, @b])
151
+ tree.add(@a, ['one']){tokens << 1}
152
+ tree.add(@a, ['two']){tokens << 2}
153
+
154
+ tree.add(@b, ['one']){tokens << 1}
155
+ tree.add(@b, ['three']){tokens << 2}
156
+ tree.add(@b, ['four']){tokens << 4}
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,467 @@
1
+ require 'spec_helper'
2
+
3
+ describe Processor::Ffmpeg do
4
+ use_model_class(:Thing,
5
+ :video_file_name => :string,
6
+ :frame_file_name => :string)
7
+
8
+ before do
9
+ spec = self
10
+ Thing.class_eval do
11
+ has_attachment :video do
12
+ path "#{spec.temporary_directory}/video.:style.:extension"
13
+ end
14
+
15
+ has_attachment :frame do
16
+ path "#{spec.temporary_directory}/frame.:style.:extension"
17
+ end
18
+ end
19
+
20
+ thing = Thing.create(:video => test_video_file('test.mov'))
21
+ @thing = Thing.find(thing.id)
22
+ end
23
+
24
+ def ffmpeg
25
+ Bulldog::Processor::Ffmpeg.ffmpeg_command
26
+ end
27
+
28
+ def original_video_path
29
+ "#{temporary_directory}/video.original.mov"
30
+ end
31
+
32
+ def output_video_path
33
+ "#{temporary_directory}/video.output.mov"
34
+ end
35
+
36
+ def original_frame_path
37
+ "#{temporary_directory}/frame.original.jpg"
38
+ end
39
+
40
+ def configure(attachment_name, &block)
41
+ Thing.attachment_reflections[attachment_name].configure(&block)
42
+ end
43
+
44
+ def video_style(name, attributes={})
45
+ configure(:video) do
46
+ style name, attributes
47
+ end
48
+ end
49
+
50
+ def process_video(options={}, &block)
51
+ configure(:video) do
52
+ process(options.merge(:on => :event, :with => :ffmpeg), &block)
53
+ end
54
+ @thing.video.process(:event)
55
+ end
56
+
57
+ describe "when a simple conversion is performed" do
58
+ before do
59
+ video_style :output
60
+ end
61
+
62
+ it "should run ffmpeg" do
63
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-y', output_video_path)
64
+ process_video
65
+ end
66
+
67
+ it "should log the command run" do
68
+ log_path = "#{temporary_directory}/log"
69
+ open(log_path, 'w') do |file|
70
+ Bulldog.logger = Logger.new(file)
71
+ process_video
72
+ end
73
+ File.read(log_path).should include("[Bulldog] Running: #{ffmpeg}")
74
+ end
75
+ end
76
+
77
+ describe "#encode" do
78
+ it "should force an encode" do
79
+ video_style :output
80
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-y', output_video_path)
81
+ process_video{encode}
82
+ end
83
+
84
+ it "should allow overriding style attributes from parameters" do
85
+ video_style :output, :video_codec => 'libx264'
86
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-vcodec', 'libtheora', '-y', output_video_path)
87
+ process_video{encode(:video_codec => 'libtheora')}
88
+ end
89
+ end
90
+
91
+ describe "#record_frame" do
92
+ before do
93
+ @thing.video.stubs(:duration).returns(20)
94
+ end
95
+
96
+ describe "when no attachment to assign to is given" do
97
+ it "should force a frame record" do
98
+ video_style :frame, :format => 'png'
99
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-vframes', '1', '-ss', '10', '-f', 'image2', '-vcodec', 'png', '-y', "#{temporary_directory}/video.frame.png")
100
+ process_video{record_frame}
101
+ end
102
+
103
+ it "should allow overriding style attributes from parameters" do
104
+ video_style :frame, :format => 'png', :position => 5
105
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-vframes', '1', '-ss', '15', '-f', 'image2', '-vcodec', 'mjpeg', '-y', "#{temporary_directory}/video.frame.png")
106
+ process_video{record_frame(:position => 15, :codec => 'mjpeg')}
107
+ end
108
+
109
+ it "should yield the path to the block if one is given" do
110
+ video_style :frame, :format => 'jpg'
111
+ spec = self
112
+ block_run = false
113
+ Bulldog.expects(:run).once.returns('')
114
+ process_video do
115
+ record_frame do |path|
116
+ block_run = true
117
+ spec.instance_eval do
118
+ path.should == "#{temporary_directory}/video.frame.jpg"
119
+ end
120
+ end
121
+ end
122
+ block_run.should be_true
123
+ end
124
+ end
125
+
126
+ describe "when an attachment to assign to is given" do
127
+ it "should output the file to the specified attachment's original path" do
128
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-vframes', '1', '-ss', '10', '-f', 'image2', '-vcodec', 'mjpeg', '-y', original_frame_path)
129
+ process_video :styles => [:original] do
130
+ record_frame(:format => 'jpg', :assign_to => :frame)
131
+ end
132
+ end
133
+
134
+ it "should assign the file to the specified attachment" do
135
+ process_video :styles => [:original] do
136
+ record_frame(:format => 'jpg', :assign_to => :frame)
137
+ end
138
+ @thing.frame.should_not be_blank
139
+ end
140
+
141
+ it "should yield the written path to any block passed, in the context of the processor" do
142
+ context = nil
143
+ argument = nil
144
+ process_video :styles => [:original] do
145
+ record_frame(:format => 'jpg', :assign_to => :frame) do |path|
146
+ context = self
147
+ argument = path
148
+ end
149
+ end
150
+ context.should be_a(Processor::Ffmpeg)
151
+ argument.should == original_frame_path
152
+ end
153
+ end
154
+
155
+ describe "using style attributes" do
156
+ def frame_path(format)
157
+ "#{temporary_directory}/video.output.#{format}"
158
+ end
159
+
160
+ it "should record a frame at the given position" do
161
+ video_style :output, :format => 'png'
162
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-vframes', '1', '-ss', '19', '-f', 'image2', '-vcodec', 'png', '-y', frame_path('png'))
163
+ process_video{record_frame(:position => 19)}
164
+ end
165
+
166
+ it "should default to recording a frame at the halfway point" do
167
+ video_style :output, :format => 'png'
168
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-vframes', '1', '-ss', '10', '-f', 'image2', '-vcodec', 'png', '-y', frame_path('png'))
169
+ process_video{record_frame}
170
+ end
171
+
172
+ it "should record a frame at the halfway point if the given position is out of bounds" do
173
+ video_style :output, :format => 'png'
174
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-vframes', '1', '-ss', '21', '-f', 'image2', '-vcodec', 'png', '-y', frame_path('png'))
175
+ process_video{record_frame(:position => 21)}
176
+ end
177
+
178
+ it "should use the specified codec if given" do
179
+ video_style :output, :format => 'png'
180
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-vframes', '1', '-ss', '10', '-f', 'image2', '-vcodec', 'mjpeg', '-y', frame_path('png'))
181
+ process_video{record_frame(:codec => 'mjpeg')}
182
+ end
183
+
184
+ it "should use the mjpeg codec by default for jpg images" do
185
+ video_style :output, :format => 'jpg'
186
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-vframes', '1', '-ss', '10', '-f', 'image2', '-vcodec', 'mjpeg', '-y', frame_path('jpg'))
187
+ process_video{record_frame}
188
+ end
189
+
190
+ it "should use the mjpeg codec by default for jpeg images" do
191
+ video_style :output, :format => 'jpeg'
192
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-vframes', '1', '-ss', '10', '-f', 'image2', '-vcodec', 'mjpeg', '-y', frame_path('jpeg'))
193
+ process_video{record_frame}
194
+ end
195
+
196
+ it "should use the png codec by default for png images" do
197
+ video_style :output, :format => 'png'
198
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-vframes', '1', '-ss', '10', '-f', 'image2', '-vcodec', 'png', '-y', frame_path('png'))
199
+ process_video{record_frame}
200
+ end
201
+ end
202
+ end
203
+
204
+ describe "encoding style attributes" do
205
+ describe "video" do
206
+ it "should interpret '30fps' as a frame rate of 30fps" do
207
+ video_style :output, :video => '30fps'
208
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-r', '30', '-y', output_video_path)
209
+ process_video{encode}
210
+ end
211
+
212
+ it "should interpret '30FPS' as a frame rate of 30fps" do
213
+ video_style :output, :video => '30FPS'
214
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-r', '30', '-y', output_video_path)
215
+ process_video{encode}
216
+ end
217
+
218
+ it "should interpret 628kbps as a video bit rate of 628kbps" do
219
+ video_style :output, :video => '628kbps'
220
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-b', '628k', '-y', output_video_path)
221
+ process_video{encode}
222
+ end
223
+
224
+ it "should interpret any other word as a video codec" do
225
+ video_style :output, :video => 'libx264'
226
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-vcodec', 'libx264', '-y', output_video_path)
227
+ process_video{encode}
228
+ end
229
+
230
+ it "should combine multiple attributes of the video stream as given" do
231
+ video_style :output, :video => 'libx264 30fps 628kbps'
232
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-vcodec', 'libx264', '-r', '30', '-b', '628k', '-y', output_video_path)
233
+ process_video{encode}
234
+ end
235
+ end
236
+
237
+ describe "audio" do
238
+ it "should interpret '44100Hz' as a sampling frequency of 44100Hz" do
239
+ video_style :output, :audio => '44100Hz'
240
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-ar', '44100', '-y', output_video_path)
241
+ process_video{encode}
242
+ end
243
+
244
+ it "should interpret '44100hz' as a sampling frequency of 44100Hz" do
245
+ video_style :output, :audio => '44100hz'
246
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-ar', '44100', '-y', output_video_path)
247
+ process_video{encode}
248
+ end
249
+
250
+ it "should interpret '64kbps' as a sampling frequency of 64kbps" do
251
+ video_style :output, :audio => '64kbps'
252
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-ab', '64k', '-y', output_video_path)
253
+ process_video{encode}
254
+ end
255
+
256
+ it "should interpret 'mono' as 1 channel" do
257
+ video_style :output, :audio => 'mono'
258
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-ac', '1', '-y', output_video_path)
259
+ process_video{encode}
260
+ end
261
+
262
+ it "should interpret 'stereo' as 2 channels" do
263
+ video_style :output, :audio => 'stereo'
264
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-ac', '2', '-y', output_video_path)
265
+ process_video{encode}
266
+ end
267
+
268
+ it "should interpret any other word as an audio codec" do
269
+ video_style :output, :audio => 'libfaac'
270
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-acodec', 'libfaac', '-y', output_video_path)
271
+ process_video{encode}
272
+ end
273
+
274
+ it "should combine multiple attributes of the audio stream as given" do
275
+ video_style :output, :audio => 'libfaac 44100Hz 64kbps'
276
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-acodec', 'libfaac', '-ar', '44100', '-ab', '64k', '-y', output_video_path)
277
+ process_video{encode}
278
+ end
279
+ end
280
+
281
+ describe "video_codec" do
282
+ it "should set the video codec" do
283
+ video_style :output, :video_codec => 'libx264'
284
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-vcodec', 'libx264', '-y', output_video_path)
285
+ process_video{encode}
286
+ end
287
+ end
288
+
289
+ describe "frame_rate" do
290
+ it "should set the frame rate" do
291
+ video_style :output, :frame_rate => 30
292
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-r', '30', '-y', output_video_path)
293
+ process_video{encode}
294
+ end
295
+ end
296
+
297
+ describe "video_bit_rate" do
298
+ it "should set the video bit rate" do
299
+ video_style :output, :video_bit_rate => '64k'
300
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-b', '64k', '-y', output_video_path)
301
+ process_video{encode}
302
+ end
303
+ end
304
+
305
+ describe "audio_codec" do
306
+ it "should set the audio codec" do
307
+ video_style :output, :audio_codec => 'libfaac'
308
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-acodec', 'libfaac', '-y', output_video_path)
309
+ process_video{encode}
310
+ end
311
+ end
312
+
313
+ describe "sampling_rate" do
314
+ it "should set the sampling rate" do
315
+ video_style :output, :sampling_rate => 44100
316
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-ar', '44100', '-y', output_video_path)
317
+ process_video{encode}
318
+ end
319
+ end
320
+
321
+ describe "audio_bit_rate" do
322
+ it "should set the audio bit rate" do
323
+ video_style :output, :audio_bit_rate => '64k'
324
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-ab', '64k', '-y', output_video_path)
325
+ process_video{encode}
326
+ end
327
+ end
328
+
329
+ describe "channels" do
330
+ it "should set the number of channels" do
331
+ video_style :output, :channels => 2
332
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-ac', '2', '-y', output_video_path)
333
+ process_video{encode}
334
+ end
335
+ end
336
+
337
+ describe "video_preset" do
338
+ it "should set a video preset" do
339
+ video_style :output, :video_preset => 'one'
340
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-vpre', 'one', '-y', output_video_path)
341
+ process_video{encode}
342
+ end
343
+
344
+ it "should allow setting more than one video preset" do
345
+ video_style :output, :video_preset => ['one', 'two']
346
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-vpre', 'one', '-vpre', 'two', '-y', output_video_path)
347
+ process_video{encode}
348
+ end
349
+ end
350
+
351
+ describe "audio_preset" do
352
+ it "should set a audio preset" do
353
+ video_style :output, :audio_preset => 'one'
354
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-apre', 'one', '-y', output_video_path)
355
+ process_video{encode}
356
+ end
357
+
358
+ it "should allow setting more than one audio preset" do
359
+ video_style :output, :audio_preset => ['one', 'two']
360
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-apre', 'one', '-apre', 'two', '-y', output_video_path)
361
+ process_video{encode}
362
+ end
363
+ end
364
+
365
+ describe "subtitle_preset" do
366
+ it "should set a subtitle preset" do
367
+ video_style :output, :subtitle_preset => 'one'
368
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-spre', 'one', '-y', output_video_path)
369
+ process_video{encode}
370
+ end
371
+
372
+ it "should allow setting more than one subtitle preset" do
373
+ video_style :output, :subtitle_preset => ['one', 'two']
374
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-spre', 'one', '-spre', 'two', '-y', output_video_path)
375
+ process_video{encode}
376
+ end
377
+ end
378
+
379
+ describe "size" do
380
+ it "should set the video size" do
381
+ video_style :output, :size => '400x300'
382
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-s', '400x300', '-y', output_video_path)
383
+ process_video{encode}
384
+ end
385
+
386
+ it "should maintain the original aspect ratio" do
387
+ video_style :output, :size => '600x600'
388
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-s', '600x450', '-y', output_video_path)
389
+ process_video{encode}
390
+ end
391
+
392
+ it "should maintain the original aspect ratio when the style size is overridden"
393
+ end
394
+
395
+ describe "num_channels" do
396
+ it "should set the number of channels" do
397
+ video_style :output, :channels => 2
398
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-ac', '2', '-y', output_video_path)
399
+ process_video{encode}
400
+ end
401
+ end
402
+
403
+ describe "deinterlaced" do
404
+ it "should set the deinterlace flag" do
405
+ video_style :output, :deinterlaced => true
406
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-deinterlace', '-y', output_video_path)
407
+ process_video{encode}
408
+ end
409
+ end
410
+
411
+ describe "pixel_format" do
412
+ it "should set the pixel format" do
413
+ video_style :output, :pixel_format => 'yuv420p'
414
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-pix_fmt', 'yuv420p', '-y', output_video_path)
415
+ process_video{encode}
416
+ end
417
+ end
418
+
419
+ describe "b_strategy" do
420
+ it "should set the b-strategy" do
421
+ video_style :output, :b_strategy => 1
422
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-b_strategy', '1', '-y', output_video_path)
423
+ process_video{encode}
424
+ end
425
+ end
426
+
427
+ describe "buffer_size" do
428
+ it "should set the video buffer verifier buffer size" do
429
+ video_style :output, :buffer_size => '2M'
430
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-bufsize', '2M', '-y', output_video_path)
431
+ process_video{encode}
432
+ end
433
+ end
434
+
435
+ describe "coder" do
436
+ it "should set the coder" do
437
+ video_style :output, :coder => 'ac'
438
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-coder', 'ac', '-y', output_video_path)
439
+ process_video{encode}
440
+ end
441
+ end
442
+
443
+ describe "verbosity" do
444
+ it "should set the verbosity" do
445
+ video_style :output, :verbosity => 1
446
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-v', '1', '-y', output_video_path)
447
+ process_video{encode}
448
+ end
449
+ end
450
+
451
+ describe "flags" do
452
+ it "should set the flags" do
453
+ video_style :output, :flags => '+loop'
454
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-flags', '+loop', '-y', output_video_path)
455
+ process_video{encode}
456
+ end
457
+ end
458
+ end
459
+
460
+ describe "#use_threads" do
461
+ it "should set the number of threads" do
462
+ video_style :output
463
+ Bulldog.expects(:run).once.with(ffmpeg, '-i', original_video_path, '-threads', '2', '-y', output_video_path)
464
+ process_video{use_threads 2}
465
+ end
466
+ end
467
+ end