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
@@ -0,0 +1,286 @@
1
+ module RVideo
2
+ module Tools
3
+ class Ffmpeg
4
+ RESOLUTION_ABBREVIATIONS = {
5
+ "sqcif" => "128x96",
6
+ "qcif" => "176x144",
7
+ "cif" => "352x288",
8
+ "4cif" => "704x576",
9
+ "qqvga" => "160x120",
10
+ "qvga" => "320x240",
11
+ "vga" => "640x480",
12
+ "svga" => "800x600",
13
+ "xga" => "1024x768",
14
+ "uxga" => "1600x1200",
15
+ "qxga" => "2048x1536",
16
+ "sxga" => "1280x1024",
17
+ "qsxga" => "2560x2048",
18
+ "hsxga" => "5120x4096",
19
+ "wvga" => "852x480",
20
+ "wxga" => "1366x768",
21
+ "wsxga" => "1600x1024",
22
+ "wuxga" => "1920x1200",
23
+ "woxga" => "2560x1600",
24
+ "wqsxga" => "3200x2048",
25
+ "wquxga" => "3840x2400",
26
+ "whsxga" => "6400x4096",
27
+ "whuxga" => "7680x4800",
28
+ "cga" => "320x200",
29
+ "ega" => "640x350",
30
+ "hd480" => "852x480",
31
+ "hd720" => "1280x720",
32
+ "hd1080" => "1920x1080"
33
+ }
34
+
35
+ VALID_ASPECT_STRINGS = ["4:3", "16:9"]
36
+ VALID_ASPECT_FLOATS = [1.3333, 1.7777]
37
+
38
+ # The flag used to set video bitrate has apparently changed between
39
+ # different ffmpeg versions. In the latest builds -b is used.
40
+ # In older builds it was -v which is now used to set verbosity of logging.
41
+ DEFAULT_VIDEO_BIT_RATE_PARAMETER = "b"
42
+ cattr_accessor :video_bit_rate_parameter
43
+ self.video_bit_rate_parameter = DEFAULT_VIDEO_BIT_RATE_PARAMETER
44
+
45
+ include AbstractTool::InstanceMethods
46
+
47
+ attr_reader :frame, :q, :size, :time, :output_bitrate, :video_size, :audio_size, :header_size, :overhead, :psnr, :output_fps
48
+
49
+ # Not sure if this is needed anymore...
50
+ def tool_command
51
+ 'ffmpeg'
52
+ end
53
+
54
+ def format_deinterlace(params={})
55
+ params[:deinterlace] ? "-deinterlace" : ""
56
+ end
57
+
58
+ def format_fps(params={})
59
+ "-r #{params[:fps]}"
60
+ end
61
+
62
+ def format_video_bit_rate(params = {})
63
+ "-#{video_bit_rate_parameter} #{params[:video_bit_rate]}k"
64
+ end
65
+
66
+ def format_video_bit_rate_tolerance(params = {})
67
+ "-bt #{params[:video_bit_rate_tolerance]}k"
68
+ end
69
+
70
+ def format_video_bit_rate_min(params = {})
71
+ "-minrate #{params[:video_bit_rate_min]}k"
72
+ end
73
+
74
+ def format_video_bit_rate_max(params = {})
75
+ "-maxrate #{params[:video_bit_rate_max]}k"
76
+ end
77
+
78
+ def format_video_quality(params={})
79
+ bitrate = params[:video_bit_rate].blank? ? nil : params[:video_bit_rate]
80
+
81
+ params.merge! get_original_fps unless params[:fps]
82
+
83
+ factor = params[:scale][:width].to_f * params[:scale][:height].to_f * params[:fps].to_f
84
+
85
+ case params[:video_quality]
86
+ when 'low'
87
+ bitrate ||= (factor / 12000).to_i
88
+ params[:video_bit_rate] = bitrate
89
+ "#{format_video_bit_rate params} -crf 30 -me zero -subq 1 -refs 1 -threads auto"
90
+ when 'medium'
91
+ bitrate ||= (factor / 9000).to_i
92
+ params[:video_bit_rate] = bitrate
93
+ "#{format_video_bit_rate params} -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"
94
+ when 'high'
95
+ bitrate ||= (factor / 3600).to_i
96
+ params[:video_bit_rate] = bitrate
97
+ "#{format_video_bit_rate params} -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"
98
+ end
99
+ end
100
+
101
+ def format_resolution(params={})
102
+ p = "-s #{params[:scale][:width]}x#{params[:scale][:height]}"
103
+ if params[:letterbox]
104
+ plr = ((params[:letterbox][:width] - params[:scale][:width]) / 2).to_i
105
+ ptb = ((params[:letterbox][:height] - params[:scale][:height]) / 2).to_i
106
+ p += " -padtop #{ptb} -padbottom #{ptb} -padleft #{plr} -padright #{plr} "
107
+ end
108
+ p
109
+ end
110
+
111
+ def format_audio_channels(params={})
112
+ "-ac #{params[:channels]}"
113
+ end
114
+
115
+ def format_audio_bit_rate(params={})
116
+ "-ab #{params[:bit_rate]}k"
117
+ end
118
+
119
+ def format_audio_sample_rate(params={})
120
+ "-ar #{params[:sample_rate]}"
121
+ end
122
+
123
+ def get_resolution
124
+ if @options['resolution'] && @options['resolution'].match(/(\d+)x(\d+)/)
125
+ @options['width'] = $1
126
+ @options['height'] = $2
127
+ get_specific_resolution
128
+ else
129
+ super
130
+ end
131
+ end
132
+
133
+ private
134
+
135
+ # Turns the temp log file into a useful string, from which we can parse the
136
+ # transcoding results.
137
+ # These log files can be enormous, so pulling the whole thing into memory is not an
138
+ # option.
139
+ def populate_raw_result(temp_file_name)
140
+ @raw_result = ""
141
+
142
+ # Is the log file exceptionally long? It's really not a big deal to pull in a thousand lines or so
143
+ # into memory. It's the gigantic files that cause problems. If the files isn't too large,
144
+ # just pull it in.
145
+ line_count = 0
146
+ if m = /^\s*(\d+)/.match(`wc -l #{temp_file_name}`)
147
+ line_count = m[1].to_i
148
+ end
149
+
150
+ if line_count > 500
151
+ # Find the message indicating that the command is actually running.
152
+ running_string = "Press .* to stop encoding"
153
+ @raw_result << `grep "#{running_string}" #{temp_file_name}`
154
+ end
155
+
156
+ # Append the bottom of the log file, where the interesting bits live.
157
+ @raw_result << `tail -n 500 #{temp_file_name}`
158
+ end
159
+
160
+ def parse_result(result)
161
+ if m = /Expected .+ for (.+) but found: (.+)/.match(result)
162
+ raise TranscoderError::InvalidCommand, m.to_s
163
+ end
164
+
165
+ if m = /Unable for find a suitable output format for.*$/.match(result)
166
+ raise TranscoderError::InvalidCommand, m[0]
167
+ end
168
+
169
+ if m = /Unknown codec \'(.*)\'/.match(result)
170
+ raise TranscoderError::InvalidFile, "Codec #{m[1]} not supported by this build of ffmpeg"
171
+ end
172
+
173
+ if m = /could not find codec parameters/.match(result)
174
+ raise TranscoderError::InvalidFile, "Codec not supported by this build of ffmpeg"
175
+ end
176
+
177
+ if m = /I\/O error occured\n(.*)$/.match(result)
178
+ raise TranscoderError::InvalidFile, "I/O error: #{m[1].strip}"
179
+ end
180
+
181
+ if m = /\n(.*)Unknown Format$/.match(result)
182
+ raise TranscoderError::InvalidFile, "unknown format (#{m[1]})"
183
+ end
184
+
185
+ if m = /\nERROR.*/m.match(result)
186
+ raise TranscoderError::InvalidFile, m[0]
187
+ end
188
+
189
+ if m = /[(\S+) @ \d+x\d+]error, (.+?)/.match(result)
190
+ raise TranscoderError::InvalidFile, "#{m[1]}: #{m[2]}"
191
+ end
192
+
193
+ if result =~ /usage: ffmpeg/
194
+ raise TranscoderError::InvalidCommand, "must pass a command to ffmpeg"
195
+ end
196
+
197
+ if result =~ /Output file does not contain.*stream/
198
+ raise TranscoderError, "Output file does not contain any video or audio streams."
199
+ end
200
+
201
+ if m = /Unsupported codec.*id=(.*)\).*for input stream\s*(.*)\s*/.match(result)
202
+ inspect_original if @original.nil?
203
+ case m[2]
204
+ when @original.audio_stream_id
205
+ codec_type = "audio"
206
+ codec = @original.audio_codec
207
+ when @original.video_stream_id
208
+ codec_type = "video"
209
+ codec = @original.video_codec
210
+ else
211
+ codec_type = "video or audio"
212
+ codec = "unknown"
213
+ end
214
+
215
+ raise TranscoderError::InvalidFile, "Unsupported #{codec_type} codec: #{codec} (id=#{m[1]}, stream=#{m[2]})"
216
+ #raise TranscoderError, "Codec #{m[1]} not supported (in stream #{m[2]})"
217
+ end
218
+
219
+ # Could not open './spec/../config/../tmp/processed/1/kites-1.avi'
220
+ if result =~ /Could not open .#{@output_file}.\Z/
221
+ raise TranscoderError, "Could not write output file to #{@output_file}"
222
+ end
223
+
224
+ full_details = /Press .* to stop encoding\n(.*)/m.match(result)
225
+ raise TranscoderError, "Unexpected result details (#{result})" if full_details.nil?
226
+ details = full_details[1].strip.gsub(/\s*\n\s*/," - ")
227
+
228
+ if details =~ /Could not write header/
229
+ raise TranscoderError, details
230
+ end
231
+
232
+ #frame= 584 q=6.0 Lsize= 708kB time=19.5 bitrate= 297.8kbits/s
233
+ #video:49kB audio:153kB global headers:0kB muxing overhead 250.444444%
234
+
235
+ #frame= 4126 q=31.0 Lsize= 5917kB time=69.1 bitrate= 702.0kbits/s
236
+ #video:2417kB audio:540kB global headers:0kB muxing overhead 100.140277%
237
+
238
+ #frame= 273 fps= 31 q=10.0 Lsize= 398kB time=5.9 bitrate= 551.8kbits/s
239
+ #video:284kB audio:92kB global headers:0kB muxing overhead 5.723981%
240
+
241
+ #mdb:94, lastbuf:0 skipping granule 0
242
+ #size= 1080kB time=69.1 bitrate= 128.0kbits /s
243
+ #video:0kB audio:1080kB global headers:0kB muxing overhead 0.002893%
244
+
245
+ #size= 80kB time=5.1 bitrate= 128.0kbits/s ^Msize= 162kB time=10.3 bitrate= 128.0kbits/s ^Msize= 241kB time=15.4 bitrate= 128.0kbits/s ^Msize= 329kB time=21.1 bitrate= 128.0kbits/s ^Msize= 413kB time=26.4 bitrate= 128.0kbits/s ^Msize= 506kB time=32.4 bitrate= 128.0kbits/s ^Msize= 591kB time=37.8 bitrate= 128.0kbits/s ^Msize= 674kB time=43.2 bitrate= 128.0kbits/s ^Msize= 771kB time=49.4 bitrate= 128.0kbits/s ^Msize= 851kB time=54.5 bitrate= 128.0kbits/s ^Msize= 932kB time=59.6 bitrate= 128.0kbits/s ^Msize= 1015kB time=64.9 bitrate= 128.0kbits/s ^Msize= 1094kB time=70.0 bitrate= 128.0kbits/s ^Msize= 1175kB time=75.2 bitrate= 128.0kbits/s ^Msize= 1244kB time=79.6 bitrate= 128.0kbits/s ^Msize= 1335kB time=85.4 bitrate= 128.0kbits/s ^Msize= 1417kB time=90.7 bitrate= 128.0kbits/s ^Msize= 1508kB time=96.5 bitrate= 128.0kbits/s ^Msize= 1589kB time=101.7 bitrate= 128.0kbits/s ^Msize= 1671kB time=106.9 bitrate= 128.0kbits/s ^Msize= 1711kB time=109.5 bitrate= 128.0kbits/s - video:0kB audio:1711kB global headers:0kB muxing overhead 0.001826%
246
+
247
+ #mdb:14, lastbuf:0 skipping granule 0 - overread, skip -5 enddists: -2 -2 - overread, skip -5 enddists: -2 -2 - size= 90kB time=5.7 bitrate= 128.0kbits/s \nsize= 189kB time=12.1 bitrate= 128.0kbits/s
248
+
249
+ #size= 59kB time=20.2 bitrate= 24.0kbits/s \nsize= 139kB time=47.4 bitrate= 24.0kbits/s \nsize= 224kB time=76.5 bitrate= 24.0kbits/s \nsize= 304kB time=103.7 bitrate= 24.0kbits/s \nsi
250
+
251
+ #mdb:14, lastbuf:0 skipping granule 0 - overread, skip -5 enddists: -2 -2 - overread, skip -5 enddists: -2 -2 - size= 81kB time=10.3 bitrate= 64.0kbits/s \nsize= 153kB time=19.6 bitrate= 64.0kbits/s
252
+
253
+ #size= 65kB time=4.1 bitrate= 128.1kbits/s \nsize= 119kB time=7.6 bitrate= 128.0kbits/s \nsize= 188kB time=12.0 bitrate= 128.0kbits/s \nsize= 268kB time=17.1 bitrate= 128.0kbits/s \nsize=
254
+
255
+ #Error while decoding stream #0.1 [mpeg4aac @ 0xb7d089f0]faac: frame decoding failed: Gain control not yet implementedError while decoding stream #0.1frame= 2143 fps= 83 q=4.0 size= 4476kB time=71.3 bitrate= 514.5kbits/s ^M[mpeg4aac @ 0xb7d089f0]faac: frame decoding failed: Gain control not yet implementedError while decoding stream #0.1
256
+
257
+ # NOTE: had to remove "\s" from "\s.*L.*size=" from this regexp below.
258
+ # Not sure why. Unit tests were succeeding, but hand tests weren't.
259
+ if details =~ /video:/
260
+ #success = /^frame=\s*(\S*)\s*q=(\S*).*L.*size=\s*(\S*)\s*time=\s*(\S*)\s*bitrate=\s*(\S*)\s*/m.match(details)
261
+ @frame = details[/frame=\s*(\S*)/, 1]
262
+ @output_fps = details[/fps=\s*(\S*)/, 1]
263
+ @q = details[/\s+q=\s*(\S*)/, 1]
264
+ @size = details[/size=\s*(\S*)/, 1]
265
+ @time = details[/time=\s*(\S*)/, 1]
266
+ @output_bitrate = details[/bitrate=\s*(\S*)/, 1]
267
+
268
+ @video_size = details[/video:\s*(\S*)/, 1]
269
+ @audio_size = details[/audio:\s*(\S*)/, 1]
270
+ @header_size = details[/headers:\s*(\S*)/, 1]
271
+ @overhead = details[/overhead[:]*\s*(\S*)/, 1]
272
+
273
+ psnr_match = /PSNR=(.*)\s*size=/.match(details)
274
+ @psnr = psnr_match[1].strip if psnr_match
275
+ return true
276
+ end
277
+
278
+ #[mp3 @ 0x54340c]flv doesnt support that sample rate, choose from (44100, 22050, 11025)
279
+ #Could not write header for output file #0 (incorrect codec parameters ?)
280
+
281
+ raise TranscoderError::UnexpectedResult, details
282
+ end
283
+
284
+ end
285
+ end
286
+ end
@@ -0,0 +1,42 @@
1
+ module RVideo
2
+ module Tools
3
+ class Ffmpeg2theora
4
+ include AbstractTool::InstanceMethods
5
+
6
+ attr_reader :raw_metadata
7
+
8
+ def tool_command
9
+ 'ffmpeg2theora'
10
+ end
11
+
12
+ def format_video_quality(params={})
13
+ bitrate = params[:video_bit_rate].blank? ? nil : params[:video_bit_rate]
14
+ factor = (params[:scale][:width].to_f * params[:scale][:height].to_f * params[:fps].to_f)
15
+ case params[:video_quality]
16
+ when 'low'
17
+ " -v 1 "
18
+ when 'medium'
19
+ "-v 5 "
20
+ when 'high'
21
+ "-v 10 "
22
+ else
23
+ ""
24
+ end
25
+ end
26
+
27
+ def parse_result(result)
28
+ if m = /does not exist or has an unknown data format/.match(result)
29
+ raise TranscoderError::InvalidFile, "I/O error"
30
+ end
31
+
32
+ if m = /General output options/.match(result)
33
+ raise TranscoderError::InvalidCommand, "no command passed to ffmpeg2theora, or no output file specified"
34
+ end
35
+
36
+ @raw_metadata = result.empty? ? "No Results" : result
37
+ return true
38
+ end
39
+
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,50 @@
1
+ # Warning: If you're dealing with large files, you should consider using yamdi instead.
2
+ module RVideo
3
+ module Tools
4
+ class Flvtool2
5
+ include AbstractTool::InstanceMethods
6
+
7
+ attr_reader :raw_metadata
8
+
9
+ #attr_reader :has_key_frames, :cue_points, :audiodatarate, :has_video, :stereo, :can_seek_to_end, :framerate, :audiosamplerate, :videocodecid, :datasize, :lasttimestamp,
10
+ # :audiosamplesize, :audiosize, :has_audio, :audiodelay, :videosize, :metadatadate, :metadatacreator, :lastkeyframetimestamp, :height, :filesize, :has_metadata, :audiocodecid,
11
+ # :duration, :videodatarate, :has_cue_points, :width
12
+
13
+ def tool_command
14
+ 'flvtool2'
15
+ end
16
+
17
+ private
18
+
19
+ def parse_result(result)
20
+ if result.empty?
21
+ return true
22
+ end
23
+
24
+ if m = /ERROR: No such file or directory(.*)\n/.match(result)
25
+ raise TranscoderError::InputFileNotFound, m[0]
26
+ end
27
+
28
+ if m = /ERROR: IO is not a FLV stream/.match(result)
29
+ raise TranscoderError::InvalidFile, "input must be a valid FLV file"
30
+ end
31
+
32
+ if m = /Copyright.*Norman Timmler/i.match(result)
33
+ raise TranscoderError::InvalidCommand, "command printed flvtool2 help text (and presumably didn't execute)"
34
+ end
35
+
36
+ if m = /ERROR: undefined method .?timestamp.? for nil/.match(result)
37
+ raise TranscoderError::InvalidFile, "Output file was empty (presumably)"
38
+ end
39
+
40
+ if m = /\A---(.*)...\Z/m.match(result)
41
+ @raw_metadata = m[0]
42
+ return true
43
+ end
44
+
45
+ raise TranscoderError::UnexpectedResult, result
46
+ end
47
+
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,103 @@
1
+ module RVideo
2
+ module Tools
3
+ class Mencoder
4
+ include AbstractTool::InstanceMethods
5
+
6
+ attr_reader :frame, :size, :time, :bitrate, :video_size, :audio_size, :output_fps
7
+
8
+ def tool_command
9
+ 'mencoder'
10
+ end
11
+
12
+ def format_fps(params={})
13
+ " -ofps #{params[:fps]}"
14
+ end
15
+
16
+ def format_resolution(params={})
17
+ p = " -vf scale=#{params[:scale][:width]}:#{params[:scale][:height]}"
18
+ if params[:letterbox]
19
+ p += ",expand=#{params[:letterbox][:width]}:#{params[:letterbox][:height]}"
20
+ end
21
+ p += ",harddup"
22
+ end
23
+
24
+ def format_audio_channels(params={})
25
+ " -channels #{params[:channels]}"
26
+ end
27
+
28
+ def format_audio_bit_rate(params={})
29
+ " br=#{params[:bit_rate]}:"
30
+ end
31
+
32
+ def format_audio_sample_rate(params={})
33
+ " -srate #{params[:sample_rate]}"
34
+ end
35
+
36
+ def format_video_quality(params={})
37
+ bitrate = params[:video_bit_rate].blank? ? nil : params[:video_bit_rate]
38
+ factor = (params[:scale][:width].to_f * params[:scale][:height].to_f * params[:fps].to_f)
39
+ case params[:video_quality]
40
+ when 'low'
41
+ bitrate ||= (factor / 12000).to_i
42
+ " -x264encopts threads=auto:subq=1:me=dia:frameref=1:crf=30:bitrate=#{bitrate} "
43
+ when 'medium'
44
+ bitrate ||= (factor / 9000).to_i
45
+ " -x264encopts threads=auto:subq=3:me=hex:frameref=2:crf=22:bitrate=#{bitrate} "
46
+ when 'high'
47
+ bitrate ||= (factor / 3600).to_i
48
+ " -x264encopts threads=auto:subq=6:me=dia:frameref=3:crf=18:bitrate=#{bitrate} "
49
+ else
50
+ ""
51
+ end
52
+ end
53
+
54
+
55
+
56
+ private
57
+
58
+ def parse_result(result)
59
+ if m = /Exiting.*No output file specified/.match(result)
60
+ raise TranscoderError::InvalidCommand, "no command passed to mencoder, or no output file specified"
61
+ end
62
+
63
+ if m = /counldn't set specified parameters, exiting/.match(result)
64
+ raise TranscoderError::InvalidCommand, "a combination of the recipe parameters is invalid: #{result}"
65
+ end
66
+
67
+ if m = /Sorry, this file format is not recognized\/supported/.match(result)
68
+ raise TranscoderError::InvalidFile, "unknown format"
69
+ end
70
+
71
+ if m = /Cannot open file\/device./.match(result)
72
+ raise TranscoderError::InvalidFile, "I/O error"
73
+ end
74
+
75
+ if m = /File not found:$/.match(result)
76
+ raise TranscoderError::InvalidFile, "I/O error"
77
+ end
78
+
79
+ video_details = result.match /Video stream:(.*)$/
80
+ if video_details
81
+ @bitrate = video_details[0][/Video stream:\s*([0-9.]*)/, 1]
82
+ @video_size = video_details[0][/size:\s*(\d*)\s*(\S*)/, 1]
83
+ @time = video_details[0][/bytes\s*([0-9.]*)/, 1]
84
+ @frame = video_details[0][/secs\s*(\d*)/, 1]
85
+ @output_fps = (@frame.to_f / @time.to_f).round_to(3)
86
+
87
+ elsif result =~ /Video stream is mandatory/
88
+ raise TranscoderError::InvalidFile,
89
+ "Video stream required, and no video stream found"
90
+ end
91
+
92
+ audio_details = result.match /Audio stream:(.*)$/
93
+ if audio_details
94
+ @audio_size = audio_details[0][/size:\s*(\d*)\s*\S*/, 1]
95
+ else
96
+ @audio_size = 0
97
+ end
98
+ @size = (@video_size.to_i + @audio_size.to_i).to_s
99
+ end
100
+
101
+ end
102
+ end
103
+ end