Class: RVideo::Inspector
- Inherits:
-
Object
- Object
- RVideo::Inspector
- Defined in:
- lib/rvideo/inspector.rb
Instance Attribute Summary collapse
-
#ffmpeg_binary ⇒ Object
Returns the value of attribute ffmpeg_binary.
-
#filename ⇒ Object
readonly
Returns the value of attribute filename.
-
#full_filename ⇒ Object
readonly
Returns the value of attribute full_filename.
-
#path ⇒ Object
readonly
Returns the value of attribute path.
-
#raw_metadata ⇒ Object
readonly
Returns the value of attribute raw_metadata.
-
#raw_response ⇒ Object
readonly
Returns the value of attribute raw_response.
Instance Method Summary collapse
-
#audio? ⇒ Boolean
Does the file have an audio stream?.
-
#audio_bit_rate ⇒ Object
:nodoc:.
- #audio_channels ⇒ Object
-
#audio_channels_string ⇒ Object
The channels used in the audio stream.
-
#audio_codec ⇒ Object
The audio codec used.
-
#audio_sample_rate ⇒ Object
The sampling rate of the audio stream.
-
#audio_sample_units ⇒ Object
The units used for the sampling rate.
- #audio_stream ⇒ Object
-
#audio_stream_id ⇒ Object
The ID of the audio stream (useful for troubleshooting).
-
#bitrate ⇒ Object
The bitrate of the movie.
-
#bitrate_units ⇒ Object
The bitrate units used.
- #calculate_time(timecode) ⇒ Object
-
#capture_frame(timecode, output_file = nil, dimension = nil) ⇒ Object
Take a screengrab of a movie.
-
#container ⇒ Object
Returns the container format for the file.
-
#duration ⇒ Object
The duration of the movie in milliseconds, as an integer.
-
#ffmpeg_build ⇒ Object
Returns the build description for ffmpeg.
-
#ffmpeg_configuration ⇒ Object
Returns the configuration options used to build ffmpeg.
-
#ffmpeg_libav ⇒ Object
Returns the versions of libavutil, libavcodec, and libavformat used by ffmpeg.
-
#ffmpeg_version ⇒ Object
Returns the version of ffmpeg used, In practice, this may or may not be useful.
-
#fps ⇒ Object
The frame rate of the video in frames per second.
-
#height ⇒ Object
The height of the video in pixels.
-
#initialize(options = {}) ⇒ Inspector
constructor
To inspect a video or audio file, initialize an Inspector object.
-
#invalid? ⇒ Boolean
Returns false if the file can be read successfully.
-
#raw_duration ⇒ Object
The duration of the movie, as a string.
-
#resolution ⇒ Object
width x height, as a string.
-
#unknown_format? ⇒ Boolean
True if the format is not understood (“Unknown Format”).
-
#unreadable_file? ⇒ Boolean
True if the file is not readable (“Duration: N/A, bitrate: N/A”).
-
#valid? ⇒ Boolean
Returns true if the file can be read successfully.
-
#video? ⇒ Boolean
Does the file have a video stream?.
-
#video_codec ⇒ Object
The video codec used.
-
#video_colorspace ⇒ Object
The colorspace of the video stream.
- #video_stream ⇒ Object
-
#video_stream_id ⇒ Object
The ID of the video stream (useful for troubleshooting).
-
#width ⇒ Object
The width of the video in pixels.
Constructor Details
#initialize(options = {}) ⇒ Inspector
To inspect a video or audio file, initialize an Inspector object.
file = RVideo::Inspector.new()
Inspector accepts three options: file, raw_response, and ffmpeg_binary. Either raw_response or file is required; ffmpeg binary is optional.
:file is a path to a file to be inspected.
:raw_response is the full output of “ffmpeg -i [file]”. If the :raw_response option is used, RVideo will not actually inspect a file; it will simply parse the provided response. This is useful if your application has already collected the ffmpeg -i response, and you don’t want to call it again.
:ffmpeg_binary is an optional argument that specifies the path to the ffmpeg binary to be used. If a path is not explicitly declared, RVideo will assume that ffmpeg exists in the Unix path. Type “which ffmpeg” to check if ffmpeg is installed and exists in your operating system’s path.
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/rvideo/inspector.rb', line 30 def initialize( = {}) if [:raw_response] @raw_response = [:raw_response] elsif [:file] if [:ffmpeg_binary] @ffmpeg_binary = [:ffmpeg_binary] raise RuntimeError, "ffmpeg could not be found (trying #{@ffmpeg_binary})" unless FileTest.exist?(@ffmpeg_binary) else # assume it is in the unix path raise RuntimeError, 'ffmpeg could not be found (expected ffmpeg to be found in the Unix path)' unless FileTest.exist?(`which ffmpeg`.chomp) @ffmpeg_binary = "ffmpeg" end file = [:file] @filename = File.basename(file) @path = File.dirname(file) @full_filename = file raise TranscoderError::InputFileNotFound, "File not found (#{@full_filename})" unless FileTest.exist?(@full_filename) @raw_response = `#{@ffmpeg_binary} -i #{Shellwords.shellescape @full_filename} 2>&1` else raise ArgumentError, "Must supply either an input file or a pregenerated response" if [:raw_response].nil? and file.nil? end = if /Unknown format/i.match(@raw_response) || .nil? @unknown_format = true elsif /Duration: N\/A/im.match(@raw_response) # elsif /Duration: N\/A|bitrate: N\/A/im.match(@raw_response) @unreadable_file = true @raw_metadata = [1] # in this case, we can at least still get the container type else @raw_metadata = [1] end end |
Instance Attribute Details
#ffmpeg_binary ⇒ Object
Returns the value of attribute ffmpeg_binary.
6 7 8 |
# File 'lib/rvideo/inspector.rb', line 6 def ffmpeg_binary @ffmpeg_binary end |
#filename ⇒ Object (readonly)
Returns the value of attribute filename.
4 5 6 |
# File 'lib/rvideo/inspector.rb', line 4 def filename @filename end |
#full_filename ⇒ Object (readonly)
Returns the value of attribute full_filename.
4 5 6 |
# File 'lib/rvideo/inspector.rb', line 4 def full_filename @full_filename end |
#path ⇒ Object (readonly)
Returns the value of attribute path.
4 5 6 |
# File 'lib/rvideo/inspector.rb', line 4 def path @path end |
#raw_metadata ⇒ Object (readonly)
Returns the value of attribute raw_metadata.
4 5 6 |
# File 'lib/rvideo/inspector.rb', line 4 def @raw_metadata end |
#raw_response ⇒ Object (readonly)
Returns the value of attribute raw_response.
4 5 6 |
# File 'lib/rvideo/inspector.rb', line 4 def raw_response @raw_response end |
Instance Method Details
#audio? ⇒ Boolean
Does the file have an audio stream?
114 115 116 117 118 119 120 |
# File 'lib/rvideo/inspector.rb', line 114 def audio? if audio_match.nil? false else true end end |
#audio_bit_rate ⇒ Object
:nodoc:
341 342 343 |
# File 'lib/rvideo/inspector.rb', line 341 def audio_bit_rate # :nodoc: nil end |
#audio_channels ⇒ Object
410 411 412 413 414 415 416 417 418 419 420 421 422 423 |
# File 'lib/rvideo/inspector.rb', line 410 def audio_channels return nil unless audio? case audio_match[5] when "mono" 1 when "stereo" 2 when "5.1" 6 else raise RuntimeError, "Unknown number of channels: #{audio_match[5]}" end end |
#audio_channels_string ⇒ Object
The channels used in the audio stream.
Examples:
"stereo"
"mono"
"5:1"
404 405 406 407 408 |
# File 'lib/rvideo/inspector.rb', line 404 def audio_channels_string return nil unless audio? audio_match[5] end |
#audio_codec ⇒ Object
The audio codec used.
Example:
"aac"
361 362 363 364 365 |
# File 'lib/rvideo/inspector.rb', line 361 def audio_codec return nil unless audio? audio_match[2] end |
#audio_sample_rate ⇒ Object
The sampling rate of the audio stream.
Example:
44100
375 376 377 378 379 |
# File 'lib/rvideo/inspector.rb', line 375 def audio_sample_rate return nil unless audio? audio_match[3].to_i end |
#audio_sample_units ⇒ Object
The units used for the sampling rate. May always be Hz.
Example:
"Hz"
389 390 391 392 393 |
# File 'lib/rvideo/inspector.rb', line 389 def audio_sample_units return nil unless audio? audio_match[4] end |
#audio_stream ⇒ Object
345 346 347 348 349 350 351 |
# File 'lib/rvideo/inspector.rb', line 345 def audio_stream return nil unless valid? #/\n\s*Stream.*Audio:.*\n/.match(@raw_response)[0].strip match = /\n\s*Stream.*Audio:.*\n/.match(@raw_response) return match[0].strip if match end |
#audio_stream_id ⇒ Object
The ID of the audio stream (useful for troubleshooting).
Example:
#0.1
432 433 434 435 436 |
# File 'lib/rvideo/inspector.rb', line 432 def audio_stream_id return nil unless audio? audio_match[1] end |
#bitrate ⇒ Object
The bitrate of the movie.
Example:
3132
321 322 323 324 325 |
# File 'lib/rvideo/inspector.rb', line 321 def bitrate return nil unless valid? bitrate_match[1].to_i end |
#bitrate_units ⇒ Object
The bitrate units used. In practice, this may always be kb/s.
Example:
"kb/s"
335 336 337 338 339 |
# File 'lib/rvideo/inspector.rb', line 335 def bitrate_units return nil unless valid? bitrate_match[2] end |
#calculate_time(timecode) ⇒ Object
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 |
# File 'lib/rvideo/inspector.rb', line 184 def calculate_time(timecode) m = /\A([0-9\.\,]*)(s|f|%)?\Z/.match(timecode) if m.nil? or m[1].nil? or m[1].empty? raise TranscoderError::ParameterError, "Invalid timecode for frame capture: #{timecode}. Must be a number, optionally followed by s, f, or %." end case m[2] when "s", nil t = m[1].to_f when "f" t = m[1].to_f / fps.to_f when "%" # milliseconds / 1000 * percent / 100 t = (duration.to_i / 1000.0) * (m[1].to_f / 100.0) else raise TranscoderError::ParameterError, "Invalid timecode for frame capture: #{timecode}. Must be a number, optionally followed by s, f, or p." end if (t * 1000) > duration calculate_time("99%") else t end end |
#capture_frame(timecode, output_file = nil, dimension = nil) ⇒ Object
Take a screengrab of a movie. Requires an input file and a time parameter, and optionally takes an output filename. If no output filename is specfied, constructs one.
Three types of time parameters are accepted - percentage (e.g. 3%), time in seconds (e.g. 60 seconds), and raw frame (e.g. 37). Will raise an exception if the time in seconds or the frame are out of the bounds of the input file.
Types:
37s (37 seconds)
37f (frame 37)
37% (37 percent)
37 (default to seconds)
If a time is outside of the duration of the file, it will choose a frame at the 99% mark.
Example:
t = RVideo::Transcoder.new('path/to/input_file.mp4')
t.capture_frame('10%') # => '/path/to/screenshot/input-10p.jpg'
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
# File 'lib/rvideo/inspector.rb', line 153 def capture_frame(timecode, output_file = nil, dimension=nil) t = calculate_time(timecode) unless output_file output_file = "#{TEMP_PATH}/#{File.basename(@full_filename, ".*")}-#{timecode.gsub("%","p")}.jpg" end # do the work # mplayer $input_file$ -ss $start_time$ -frames 1 -vo jpeg -o $output_file$ # ffmpeg -i $input_file$ -v nopb -ss $start_time$ -b $bitrate$ -an -vframes 1 -y $output_file$ dimension_option="" dimension_option="-s #{dimension}" unless dimension.nil? command = "ffmpeg -i #{@full_filename} -ss #{t} -t 00:00:01 -r 1 -vframes 1 #{dimension_option} -f image2 #{output_file}" Transcoder.logger.info("\nCreating Screenshot: #{command}\n") frame_result = `#{command} 2>&1` # Different versions of ffmpeg report errors differently when a screenshot cannot be extracted from # a video given its set of options. Some versions return a non-zero exit code and report errors while # others simply unless File.exists?(output_file) msg = <<-EOT.gsub(/(^\s+|\n)/, '') This means that ffmpeg could not extract a screenshot from the video. It may indicate that the video file was corrupt or that the requested frame to be captured was outside the length of the video. Full command: #{command} EOT Transcoder.logger.error msg raise TranscoderError::OutputFileNotFound, msg end Transcoder.logger.info("\nScreenshot results: #{frame_result}") output_file end |
#container ⇒ Object
Returns the container format for the file. Instead of returning a single format, this may return a string of related formats.
Examples:
"avi"
"mov,mp4,m4a,3gp,3g2,mj2"
275 276 277 278 279 |
# File 'lib/rvideo/inspector.rb', line 275 def container return nil if @unknown_format /Input \#\d+\,\s*(\S+),\s*from/.match(@raw_metadata)[1] end |
#duration ⇒ Object
The duration of the movie in milliseconds, as an integer.
Example:
24400 # 24.4 seconds
Note that the precision of the duration is in tenths of a second, not thousandths, but milliseconds are a more standard unit of time than deciseconds.
306 307 308 309 310 311 |
# File 'lib/rvideo/inspector.rb', line 306 def duration return nil unless valid? units = raw_duration.split(":") (units[0].to_i * 60 * 60 * 1000) + (units[1].to_i * 60 * 1000) + (units[2].to_f * 1000).to_i end |
#ffmpeg_build ⇒ Object
Returns the build description for ffmpeg.
Example:
built on Apr 15 2006 04:58:19, gcc: 4.0.1 (Apple Computer, Inc. build
5250)
260 261 262 |
# File 'lib/rvideo/inspector.rb', line 260 def ffmpeg_build /(\n\s*)(built on.*)(\n)/.match(@raw_response)[2] end |
#ffmpeg_configuration ⇒ Object
Returns the configuration options used to build ffmpeg.
Example:
--enable-mp3lame --enable-gpl --disable-ffplay --disable-ffserver
--enable-a52 --enable-xvid
232 233 234 |
# File 'lib/rvideo/inspector.rb', line 232 def ffmpeg_configuration /(\s*configuration:)(.*)\n/.match(@raw_response)[2].strip end |
#ffmpeg_libav ⇒ Object
Returns the versions of libavutil, libavcodec, and libavformat used by ffmpeg.
Example:
libavutil version: 49.0.0
libavcodec version: 51.9.0
libavformat version: 50.4.0
247 248 249 |
# File 'lib/rvideo/inspector.rb', line 247 def ffmpeg_libav /^(\s*lib.*\n)+/.match(@raw_response)[0].split("\n").each {|l| l.strip! } end |
#ffmpeg_version ⇒ Object
Returns the version of ffmpeg used, In practice, this may or may not be useful.
Examples:
SVN-r6399
CVS
219 220 221 |
# File 'lib/rvideo/inspector.rb', line 219 def ffmpeg_version @ffmpeg_version = @raw_response.split("\n").first.split("version").last.split(",").first.strip end |
#fps ⇒ Object
The frame rate of the video in frames per second
Example:
"29.97"
529 530 531 532 533 |
# File 'lib/rvideo/inspector.rb', line 529 def fps return nil unless video? /([0-9\.]+) (fps|tb)/.match(video_stream)[1] end |
#height ⇒ Object
The height of the video in pixels.
501 502 503 504 505 |
# File 'lib/rvideo/inspector.rb', line 501 def height return nil unless video? video_match[5].to_i end |
#invalid? ⇒ Boolean
Returns false if the file can be read successfully. Returns false otherwise.
82 83 84 |
# File 'lib/rvideo/inspector.rb', line 82 def invalid? !valid? end |
#raw_duration ⇒ Object
The duration of the movie, as a string.
Example:
"00:00:24.4" # 24.4 seconds
288 289 290 291 292 |
# File 'lib/rvideo/inspector.rb', line 288 def raw_duration return nil unless valid? /Duration:\s*([0-9\:\.]+),/.match(@raw_metadata)[1] end |
#resolution ⇒ Object
width x height, as a string.
Examples:
320x240
1280x720
515 516 517 518 519 |
# File 'lib/rvideo/inspector.rb', line 515 def resolution return nil unless video? "#{width}x#{height}" end |
#unknown_format? ⇒ Boolean
True if the format is not understood (“Unknown Format”)
90 91 92 93 94 95 96 |
# File 'lib/rvideo/inspector.rb', line 90 def unknown_format? if @unknown_format true else false end end |
#unreadable_file? ⇒ Boolean
True if the file is not readable (“Duration: N/A, bitrate: N/A”)
102 103 104 105 106 107 108 |
# File 'lib/rvideo/inspector.rb', line 102 def unreadable_file? if @unreadable_file true else false end end |
#valid? ⇒ Boolean
Returns true if the file can be read successfully. Returns false otherwise.
70 71 72 73 74 75 76 |
# File 'lib/rvideo/inspector.rb', line 70 def valid? if @unknown_format or @unreadable_file false else true end end |
#video? ⇒ Boolean
Does the file have a video stream?
126 127 128 129 130 131 132 |
# File 'lib/rvideo/inspector.rb', line 126 def video? if video_match.nil? false else true end end |
#video_codec ⇒ Object
The video codec used.
Example:
"mpeg4"
467 468 469 470 471 |
# File 'lib/rvideo/inspector.rb', line 467 def video_codec return nil unless video? video_match[2] end |
#video_colorspace ⇒ Object
The colorspace of the video stream.
Example:
"yuv420p"
481 482 483 484 485 |
# File 'lib/rvideo/inspector.rb', line 481 def video_colorspace return nil unless video? video_match[3] end |
#video_stream ⇒ Object
438 439 440 441 442 443 444 |
# File 'lib/rvideo/inspector.rb', line 438 def video_stream return nil unless valid? match = /\n\s*Stream.*Video:.*\n/.match(@raw_response) return match[0].strip unless match.nil? nil end |
#video_stream_id ⇒ Object
The ID of the video stream (useful for troubleshooting).
Example:
#0.0
453 454 455 456 457 |
# File 'lib/rvideo/inspector.rb', line 453 def video_stream_id return nil unless video? video_match[1] end |
#width ⇒ Object
The width of the video in pixels.
491 492 493 494 495 |
# File 'lib/rvideo/inspector.rb', line 491 def width return nil unless video? video_match[4].to_i end |