Class: RVideo::Inspector
- Inherits:
-
Object
- Object
- RVideo::Inspector
- Defined in:
- lib/rvideo/inspector.rb
Overview
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.
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
- #audio_bit_rate_units ⇒ Object
- #audio_bit_rate_with_units ⇒ Object
- #audio_channels ⇒ Object
-
#audio_channels_string ⇒ Object
The channels used in the audio stream.
-
#audio_codec ⇒ Object
The audio codec used.
-
#audio_sample_bit_depth ⇒ Object
This should almost always return 16, as the vast majority of audio is 16 bit.
-
#audio_sample_rate ⇒ Object
The sampling rate of the audio stream.
-
#audio_sample_rate_units ⇒ Object
(also: #audio_sample_units)
The units used for the sampling rate.
- #audio_sample_rate_with_units ⇒ Object
- #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.
- #bitrate_with_units ⇒ Object
- #calculate_time(timecode) ⇒ Object
-
#capture_frame(timecode, output_file = nil) ⇒ Object
Take a screengrab of a movie.
- #codec_time_base ⇒ Object
-
#container ⇒ Object
Returns the container format for the file.
- #display_aspect_ratio ⇒ Object
-
#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
(also: #framerate)
The frame rate of the video in frames per second.
-
#height ⇒ Object
The height of the video in pixels.
-
#initialize(options = {}) ⇒ Inspector
constructor
A new instance of Inspector.
- #initialize_with_file(file, ffmpeg_binary = nil) ⇒ Object
- #initialize_with_raw_response(raw_response) ⇒ Object
-
#invalid? ⇒ Boolean
Returns false if the file can be read successfully.
- #pixel_aspect_ratio ⇒ Object
-
#raw_duration ⇒ Object
The duration of the movie, as a string.
-
#resolution ⇒ Object
width x height, as a string.
- #time_base ⇒ Object
-
#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
Returns a new instance of Inspector.
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/rvideo/inspector.rb', line 26 def initialize( = {}) if not ([:raw_response] or [:file]) raise ArgumentError, "Must supply either an input file or a pregenerated response" end if [:raw_response] initialize_with_raw_response([:raw_response]) elsif [:file] initialize_with_file([:file], [:ffmpeg_binary]) end = /(Input \#.*)\n.+\n\Z/m.match(@raw_response) if /Unknown format/i.match(@raw_response) || .nil? @unknown_format = true elsif /Duration: N\/A/im.match(@raw_response) # in this case, we can at least still get the container type @unreadable_file = true @raw_metadata = [1] else @raw_metadata = [1] end end |
Instance Attribute Details
#ffmpeg_binary ⇒ Object
Returns the value of attribute ffmpeg_binary.
24 25 26 |
# File 'lib/rvideo/inspector.rb', line 24 def ffmpeg_binary @ffmpeg_binary end |
#filename ⇒ Object (readonly)
Returns the value of attribute filename.
22 23 24 |
# File 'lib/rvideo/inspector.rb', line 22 def filename @filename end |
#full_filename ⇒ Object (readonly)
Returns the value of attribute full_filename.
22 23 24 |
# File 'lib/rvideo/inspector.rb', line 22 def full_filename @full_filename end |
#path ⇒ Object (readonly)
Returns the value of attribute path.
22 23 24 |
# File 'lib/rvideo/inspector.rb', line 22 def path @path end |
#raw_metadata ⇒ Object (readonly)
Returns the value of attribute raw_metadata.
22 23 24 |
# File 'lib/rvideo/inspector.rb', line 22 def @raw_metadata end |
#raw_response ⇒ Object (readonly)
Returns the value of attribute raw_response.
22 23 24 |
# File 'lib/rvideo/inspector.rb', line 22 def raw_response @raw_response end |
Instance Method Details
#audio? ⇒ Boolean
Does the file have an audio stream?
100 101 102 |
# File 'lib/rvideo/inspector.rb', line 100 def audio? not audio_match.nil? end |
#audio_bit_rate ⇒ Object
283 284 285 286 |
# File 'lib/rvideo/inspector.rb', line 283 def audio_bit_rate return nil unless audio? audio_match[7].to_i end |
#audio_bit_rate_units ⇒ Object
288 289 290 291 |
# File 'lib/rvideo/inspector.rb', line 288 def audio_bit_rate_units return nil unless audio? audio_match[8] end |
#audio_bit_rate_with_units ⇒ Object
293 294 295 |
# File 'lib/rvideo/inspector.rb', line 293 def audio_bit_rate_with_units "#{audio_bit_rate} #{audio_bit_rate_units}" end |
#audio_channels ⇒ Object
354 355 356 357 358 359 360 361 362 363 |
# File 'lib/rvideo/inspector.rb', line 354 def audio_channels return nil unless audio? case audio_match[5] when "mono" then 1 when "stereo" then 2 else raise RuntimeError, "Unknown number of channels: #{audio_channels}" end end |
#audio_channels_string ⇒ Object
The channels used in the audio stream.
Examples:
"stereo"
"mono"
"5:1"
349 350 351 352 |
# File 'lib/rvideo/inspector.rb', line 349 def audio_channels_string return nil unless audio? audio_match[5] end |
#audio_codec ⇒ Object
The audio codec used.
Example:
"aac"
310 311 312 313 |
# File 'lib/rvideo/inspector.rb', line 310 def audio_codec return nil unless audio? audio_match[2] end |
#audio_sample_bit_depth ⇒ Object
This should almost always return 16, as the vast majority of audio is 16 bit.
367 368 369 370 |
# File 'lib/rvideo/inspector.rb', line 367 def audio_sample_bit_depth return nil unless audio? audio_match[6].to_i end |
#audio_sample_rate ⇒ Object
The sampling rate of the audio stream.
Example:
44100
321 322 323 324 |
# File 'lib/rvideo/inspector.rb', line 321 def audio_sample_rate return nil unless audio? audio_match[3].to_i end |
#audio_sample_rate_units ⇒ Object Also known as: audio_sample_units
The units used for the sampling rate. May always be Hz.
Example:
"Hz"
332 333 334 335 |
# File 'lib/rvideo/inspector.rb', line 332 def audio_sample_rate_units return nil unless audio? audio_match[4] end |
#audio_sample_rate_with_units ⇒ Object
338 339 340 |
# File 'lib/rvideo/inspector.rb', line 338 def audio_sample_rate_with_units "#{audio_sample_rate} #{audio_sample_rate_units}" end |
#audio_stream ⇒ Object
297 298 299 300 301 302 |
# File 'lib/rvideo/inspector.rb', line 297 def audio_stream return nil unless valid? match = /\n\s*Stream.*Audio:.*\n/.match(@raw_response) match[0].strip if match end |
#audio_stream_id ⇒ Object
The ID of the audio stream (useful for troubleshooting).
Example:
#0.1
377 378 379 380 |
# File 'lib/rvideo/inspector.rb', line 377 def audio_stream_id return nil unless audio? audio_match[1] end |
#bitrate ⇒ Object
The bitrate of the movie.
Example:
3132
263 264 265 266 |
# File 'lib/rvideo/inspector.rb', line 263 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"
274 275 276 277 |
# File 'lib/rvideo/inspector.rb', line 274 def bitrate_units return nil unless valid? bitrate_match[2] end |
#bitrate_with_units ⇒ Object
279 280 281 |
# File 'lib/rvideo/inspector.rb', line 279 def bitrate_with_units "#{bitrate} #{bitrate_units}" end |
#calculate_time(timecode) ⇒ Object
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/rvideo/inspector.rb', line 143 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) ⇒ 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'
131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/rvideo/inspector.rb', line 131 def capture_frame(timecode, output_file = nil) t = calculate_time(timecode) output_file ||= "#{TEMP_PATH}/#{File.basename(@full_filename, ".*")}-#{timecode.gsub("%","p")}.jpg" command = "ffmpeg -i #{@full_filename.shell_quoted} -ss #{t} -t 00:00:01 -r 1 -vframes 1 -f image2 #{output_file.shell_quoted}" RVideo.logger.info("\nCreating Screenshot: #{command}\n") frame_result = `#{command} 2>&1` RVideo.logger.info("\nScreenshot results: #{frame_result}") output_file end |
#codec_time_base ⇒ Object
471 472 473 474 |
# File 'lib/rvideo/inspector.rb', line 471 def codec_time_base return nil unless video? video_match[11] 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"
224 225 226 227 |
# File 'lib/rvideo/inspector.rb', line 224 def container return nil if @unknown_format /Input \#\d+\,\s*(\S+),\s*from/.match(@raw_metadata)[1] end |
#display_aspect_ratio ⇒ Object
449 450 451 452 |
# File 'lib/rvideo/inspector.rb', line 449 def display_aspect_ratio return nil unless video? video_match[8] 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.
250 251 252 253 254 255 |
# File 'lib/rvideo/inspector.rb', line 250 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)
211 212 213 |
# File 'lib/rvideo/inspector.rb', line 211 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
187 188 189 |
# File 'lib/rvideo/inspector.rb', line 187 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
200 201 202 |
# File 'lib/rvideo/inspector.rb', line 200 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
176 177 178 |
# File 'lib/rvideo/inspector.rb', line 176 def ffmpeg_version @ffmpeg_version = @raw_response.split("\n").first.split("version").last.split(",").first.strip end |
#fps ⇒ Object Also known as: framerate
The frame rate of the video in frames per second
Example:
"29.97"
460 461 462 463 |
# File 'lib/rvideo/inspector.rb', line 460 def fps return nil unless video? video_match[2] or video_match[9] end |
#height ⇒ Object
The height of the video in pixels.
428 429 430 431 |
# File 'lib/rvideo/inspector.rb', line 428 def height return nil unless video? video_match[6].to_i end |
#initialize_with_file(file, ffmpeg_binary = nil) ⇒ Object
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/rvideo/inspector.rb', line 54 def initialize_with_file(file, ffmpeg_binary = nil) if ffmpeg_binary @ffmpeg_binary = ffmpeg_binary if not FileTest.exist?(@ffmpeg_binary) raise "ffmpeg could not be found (trying #{@ffmpeg_binary})" end else # assume it is in the unix path if not FileTest.exist?(`which ffmpeg`.chomp) raise "ffmpeg could not be found (expected ffmpeg to be found in the Unix path)" end @ffmpeg_binary = "ffmpeg" end if not FileTest.exist?(file.gsub('"','')) raise TranscoderError::InputFileNotFound, "File not found (#{file})" end @full_filename = file @filename = File.basename(@full_filename) @path = File.dirname(@full_filename) @raw_response = `#{@ffmpeg_binary} -i #{@full_filename.shell_quoted} 2>&1` end |
#initialize_with_raw_response(raw_response) ⇒ Object
50 51 52 |
# File 'lib/rvideo/inspector.rb', line 50 def initialize_with_raw_response(raw_response) @raw_response = raw_response end |
#invalid? ⇒ Boolean
Returns false if the file can be read successfully. Returns false otherwise.
85 86 87 |
# File 'lib/rvideo/inspector.rb', line 85 def invalid? not valid? end |
#pixel_aspect_ratio ⇒ Object
444 445 446 447 |
# File 'lib/rvideo/inspector.rb', line 444 def pixel_aspect_ratio return nil unless video? video_match[7] end |
#raw_duration ⇒ Object
The duration of the movie, as a string.
Example:
"00:00:24.4" # 24.4 seconds
235 236 237 238 |
# File 'lib/rvideo/inspector.rb', line 235 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
439 440 441 442 |
# File 'lib/rvideo/inspector.rb', line 439 def resolution return nil unless video? "#{width}x#{height}" end |
#time_base ⇒ Object
466 467 468 469 |
# File 'lib/rvideo/inspector.rb', line 466 def time_base return nil unless video? video_match[10] end |
#unknown_format? ⇒ Boolean
True if the format is not understood ("Unknown Format")
90 91 92 |
# File 'lib/rvideo/inspector.rb', line 90 def unknown_format? @unknown_format ? true : false end |
#unreadable_file? ⇒ Boolean
True if the file is not readable ("Duration: N/A, bitrate: N/A")
95 96 97 |
# File 'lib/rvideo/inspector.rb', line 95 def unreadable_file? @unreadable_file ? true : false end |
#valid? ⇒ Boolean
Returns true if the file can be read successfully. Returns false otherwise.
80 81 82 |
# File 'lib/rvideo/inspector.rb', line 80 def valid? not (@unknown_format or @unreadable_file) end |
#video? ⇒ Boolean
Does the file have a video stream?
105 106 107 |
# File 'lib/rvideo/inspector.rb', line 105 def video? not video_match.nil? end |
#video_codec ⇒ Object
The video codec used.
Example:
"mpeg4"
405 406 407 408 |
# File 'lib/rvideo/inspector.rb', line 405 def video_codec return nil unless video? video_match[3] end |
#video_colorspace ⇒ Object
The colorspace of the video stream.
Example:
"yuv420p"
416 417 418 419 |
# File 'lib/rvideo/inspector.rb', line 416 def video_colorspace return nil unless video? video_match[4] end |
#video_stream ⇒ Object
382 383 384 385 386 387 |
# File 'lib/rvideo/inspector.rb', line 382 def video_stream return nil unless valid? match = /\n\s*Stream.*Video:.*\n/.match(@raw_response) match[0].strip unless match.nil? end |
#video_stream_id ⇒ Object
The ID of the video stream (useful for troubleshooting).
Example:
#0.0
394 395 396 397 |
# File 'lib/rvideo/inspector.rb', line 394 def video_stream_id return nil unless video? video_match[1] end |
#width ⇒ Object
The width of the video in pixels.
422 423 424 425 |
# File 'lib/rvideo/inspector.rb', line 422 def width return nil unless video? video_match[5].to_i end |