Class: FFMPEG::Movie
- Inherits:
-
Object
- Object
- FFMPEG::Movie
- Defined in:
- lib/ffmpeg/movie.rb
Constant Summary collapse
- UNSUPPORTED_CODEC_PATTERN =
/^Unsupported codec with id (\d+) for input stream (\d+)$/
Instance Attribute Summary collapse
-
#audio_bitrate ⇒ Object
readonly
Returns the value of attribute audio_bitrate.
-
#audio_channels ⇒ Object
readonly
Returns the value of attribute audio_channels.
-
#audio_codec ⇒ Object
readonly
Returns the value of attribute audio_codec.
-
#audio_sample_rate ⇒ Object
readonly
Returns the value of attribute audio_sample_rate.
-
#audio_stream ⇒ Object
readonly
Returns the value of attribute audio_stream.
-
#audio_streams ⇒ Object
readonly
Returns the value of attribute audio_streams.
-
#audio_tags ⇒ Object
readonly
Returns the value of attribute audio_tags.
-
#bitrate ⇒ Object
readonly
Returns the value of attribute bitrate.
-
#colorspace ⇒ Object
readonly
Returns the value of attribute colorspace.
-
#container ⇒ Object
readonly
Returns the value of attribute container.
-
#creation_time ⇒ Object
readonly
Returns the value of attribute creation_time.
-
#dar ⇒ Object
readonly
Returns the value of attribute dar.
-
#duration ⇒ Object
readonly
Returns the value of attribute duration.
-
#format_tags ⇒ Object
readonly
Returns the value of attribute format_tags.
-
#frame_rate ⇒ Object
readonly
Returns the value of attribute frame_rate.
-
#height ⇒ Object
readonly
Returns the value of attribute height.
-
#metadata ⇒ Object
readonly
Returns the value of attribute metadata.
-
#path ⇒ Object
readonly
Returns the value of attribute path.
-
#rotation ⇒ Object
readonly
Returns the value of attribute rotation.
-
#sar ⇒ Object
readonly
Returns the value of attribute sar.
-
#time ⇒ Object
readonly
Returns the value of attribute time.
-
#video_bitrate ⇒ Object
readonly
Returns the value of attribute video_bitrate.
-
#video_codec ⇒ Object
readonly
Returns the value of attribute video_codec.
-
#video_stream ⇒ Object
readonly
Returns the value of attribute video_stream.
-
#width ⇒ Object
readonly
Returns the value of attribute width.
Instance Method Summary collapse
- #audio_channel_layout ⇒ Object
- #calculated_aspect_ratio ⇒ Object
- #calculated_pixel_aspect_ratio ⇒ Object
-
#initialize(path) ⇒ Movie
constructor
A new instance of Movie.
- #local? ⇒ Boolean
- #remote? ⇒ Boolean
- #resolution ⇒ Object
- #screenshot(output_file, options = EncodingOptions.new, transcoder_options = {}, &block) ⇒ Object
- #size ⇒ Object
- #transcode(output_file, options = EncodingOptions.new, transcoder_options = {}, &block) ⇒ Object
- #unsupported_streams(std_error) ⇒ Object
- #valid? ⇒ Boolean
Constructor Details
#initialize(path) ⇒ Movie
Returns a new instance of Movie.
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 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 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
# File 'lib/ffmpeg/movie.rb', line 15 def initialize(path) @path = path if remote? @head = head raise Errno::ENOENT, "the URL '#{path}' does not exist" unless @head.is_a?(Net::HTTPSuccess) else raise Errno::ENOENT, "the file '#{path}' does not exist" unless File.exist?(path) end @path = path # ffmpeg will output to stderr command = [FFMPEG.ffprobe_binary, '-i', path, *%w(-print_format json -show_format -show_streams -show_error)] std_output = '' std_error = '' Open3.popen3(*command) do |stdin, stdout, stderr| std_output = stdout.read unless stdout.nil? std_error = stderr.read unless stderr.nil? end fix_encoding(std_output) fix_encoding(std_error) begin @metadata = MultiJson.load(std_output, symbolize_keys: true) rescue MultiJson::ParseError raise "Could not parse output from FFProbe:\n#{ std_output }" end if @metadata.key?(:error) @duration = 0 else video_streams = @metadata[:streams].select { |stream| stream.key?(:codec_type) and stream[:codec_type] === 'video' } audio_streams = @metadata[:streams].select { |stream| stream.key?(:codec_type) and stream[:codec_type] === 'audio' } @container = @metadata[:format][:format_name] @duration = @metadata[:format][:duration].to_f @time = @metadata[:format][:start_time].to_f @format_tags = @metadata[:format][:tags] @creation_time = if @format_tags and @format_tags.key?(:creation_time) begin Time.parse(@format_tags[:creation_time]) rescue ArgumentError nil end else nil end @bitrate = @metadata[:format][:bit_rate].to_i # TODO: Handle multiple video codecs (is that possible?) video_stream = video_streams.first unless video_stream.nil? @video_codec = video_stream[:codec_name] @colorspace = video_stream[:pix_fmt] @width = video_stream[:width] @height = video_stream[:height] @video_bitrate = video_stream[:bit_rate].to_i @sar = video_stream[:sample_aspect_ratio] @dar = video_stream[:display_aspect_ratio] @frame_rate = unless video_stream[:avg_frame_rate] == '0/0' Rational(video_stream[:avg_frame_rate]) else nil end @video_stream = "#{video_stream[:codec_name]} (#{video_stream[:profile]}) (#{video_stream[:codec_tag_string]} / #{video_stream[:codec_tag]}), #{colorspace}, #{resolution} [SAR #{sar} DAR #{dar}]" @rotation = if video_stream.key?(:tags) and video_stream[:tags].key?(:rotate) video_stream[:tags][:rotate].to_i else nil end end @audio_streams = audio_streams.map do |stream| { :index => stream[:index], :channels => stream[:channels].to_i, :codec_name => stream[:codec_name], :sample_rate => stream[:sample_rate].to_i, :bitrate => stream[:bit_rate].to_i, :channel_layout => stream[:channel_layout], :tags => stream[:streams], :overview => "#{stream[:codec_name]} (#{stream[:codec_tag_string]} / #{stream[:codec_tag]}), #{stream[:sample_rate]} Hz, #{stream[:channel_layout]}, #{stream[:sample_fmt]}, #{stream[:bit_rate]} bit/s" } end audio_stream = @audio_streams.first unless audio_stream.nil? @audio_channels = audio_stream[:channels] @audio_codec = audio_stream[:codec_name] @audio_sample_rate = audio_stream[:sample_rate] @audio_bitrate = audio_stream[:bitrate] @audio_channel_layout = audio_stream[:channel_layout] @audio_tags = audio_stream[:audio_tags] @audio_stream = audio_stream[:overview] end end unsupported_stream_ids = unsupported_streams(std_error) nil_or_unsupported = -> (stream) { stream.nil? || unsupported_stream_ids.include?(stream[:index]) } @invalid = true if nil_or_unsupported.(video_stream) && nil_or_unsupported.(audio_stream) @invalid = true if @metadata.key?(:error) @invalid = true if std_error.include?("could not find codec parameters") end |
Instance Attribute Details
#audio_bitrate ⇒ Object (readonly)
Returns the value of attribute audio_bitrate.
9 10 11 |
# File 'lib/ffmpeg/movie.rb', line 9 def audio_bitrate @audio_bitrate end |
#audio_channels ⇒ Object (readonly)
Returns the value of attribute audio_channels.
9 10 11 |
# File 'lib/ffmpeg/movie.rb', line 9 def audio_channels @audio_channels end |
#audio_codec ⇒ Object (readonly)
Returns the value of attribute audio_codec.
9 10 11 |
# File 'lib/ffmpeg/movie.rb', line 9 def audio_codec @audio_codec end |
#audio_sample_rate ⇒ Object (readonly)
Returns the value of attribute audio_sample_rate.
9 10 11 |
# File 'lib/ffmpeg/movie.rb', line 9 def audio_sample_rate @audio_sample_rate end |
#audio_stream ⇒ Object (readonly)
Returns the value of attribute audio_stream.
9 10 11 |
# File 'lib/ffmpeg/movie.rb', line 9 def audio_stream @audio_stream end |
#audio_streams ⇒ Object (readonly)
Returns the value of attribute audio_streams.
9 10 11 |
# File 'lib/ffmpeg/movie.rb', line 9 def audio_streams @audio_streams end |
#audio_tags ⇒ Object (readonly)
Returns the value of attribute audio_tags.
9 10 11 |
# File 'lib/ffmpeg/movie.rb', line 9 def @audio_tags end |
#bitrate ⇒ Object (readonly)
Returns the value of attribute bitrate.
7 8 9 |
# File 'lib/ffmpeg/movie.rb', line 7 def bitrate @bitrate end |
#colorspace ⇒ Object (readonly)
Returns the value of attribute colorspace.
8 9 10 |
# File 'lib/ffmpeg/movie.rb', line 8 def colorspace @colorspace end |
#container ⇒ Object (readonly)
Returns the value of attribute container.
10 11 12 |
# File 'lib/ffmpeg/movie.rb', line 10 def container @container end |
#creation_time ⇒ Object (readonly)
Returns the value of attribute creation_time.
7 8 9 |
# File 'lib/ffmpeg/movie.rb', line 7 def creation_time @creation_time end |
#dar ⇒ Object (readonly)
Returns the value of attribute dar.
8 9 10 |
# File 'lib/ffmpeg/movie.rb', line 8 def dar @dar end |
#duration ⇒ Object (readonly)
Returns the value of attribute duration.
7 8 9 |
# File 'lib/ffmpeg/movie.rb', line 7 def duration @duration end |
#format_tags ⇒ Object (readonly)
Returns the value of attribute format_tags.
11 12 13 |
# File 'lib/ffmpeg/movie.rb', line 11 def @format_tags end |
#frame_rate ⇒ Object (readonly)
Returns the value of attribute frame_rate.
8 9 10 |
# File 'lib/ffmpeg/movie.rb', line 8 def frame_rate @frame_rate end |
#height ⇒ Object (readonly)
Returns the value of attribute height.
8 9 10 |
# File 'lib/ffmpeg/movie.rb', line 8 def height @height end |
#metadata ⇒ Object (readonly)
Returns the value of attribute metadata.
11 12 13 |
# File 'lib/ffmpeg/movie.rb', line 11 def @metadata end |
#path ⇒ Object (readonly)
Returns the value of attribute path.
7 8 9 |
# File 'lib/ffmpeg/movie.rb', line 7 def path @path end |
#rotation ⇒ Object (readonly)
Returns the value of attribute rotation.
7 8 9 |
# File 'lib/ffmpeg/movie.rb', line 7 def rotation @rotation end |
#sar ⇒ Object (readonly)
Returns the value of attribute sar.
8 9 10 |
# File 'lib/ffmpeg/movie.rb', line 8 def sar @sar end |
#time ⇒ Object (readonly)
Returns the value of attribute time.
7 8 9 |
# File 'lib/ffmpeg/movie.rb', line 7 def time @time end |
#video_bitrate ⇒ Object (readonly)
Returns the value of attribute video_bitrate.
8 9 10 |
# File 'lib/ffmpeg/movie.rb', line 8 def video_bitrate @video_bitrate end |
#video_codec ⇒ Object (readonly)
Returns the value of attribute video_codec.
8 9 10 |
# File 'lib/ffmpeg/movie.rb', line 8 def video_codec @video_codec end |
#video_stream ⇒ Object (readonly)
Returns the value of attribute video_stream.
8 9 10 |
# File 'lib/ffmpeg/movie.rb', line 8 def video_stream @video_stream end |
#width ⇒ Object (readonly)
Returns the value of attribute width.
8 9 10 |
# File 'lib/ffmpeg/movie.rb', line 8 def width @width end |
Instance Method Details
#audio_channel_layout ⇒ Object
185 186 187 188 189 190 191 192 193 194 195 196 197 |
# File 'lib/ffmpeg/movie.rb', line 185 def audio_channel_layout # TODO Whenever support for ffmpeg/ffprobe 1.2.1 is dropped this is no longer needed @audio_channel_layout || case(audio_channels) when 1 'stereo' when 2 'stereo' when 6 '5.1' else 'unknown' end end |
#calculated_aspect_ratio ⇒ Object
169 170 171 |
# File 'lib/ffmpeg/movie.rb', line 169 def calculated_aspect_ratio aspect_from_dar || aspect_from_dimensions end |
#calculated_pixel_aspect_ratio ⇒ Object
173 174 175 |
# File 'lib/ffmpeg/movie.rb', line 173 def calculated_pixel_aspect_ratio aspect_from_sar || 1 end |
#local? ⇒ Boolean
151 152 153 |
# File 'lib/ffmpeg/movie.rb', line 151 def local? not remote? end |
#remote? ⇒ Boolean
147 148 149 |
# File 'lib/ffmpeg/movie.rb', line 147 def remote? @path =~ URI::regexp(%w(http https)) end |
#resolution ⇒ Object
163 164 165 166 167 |
# File 'lib/ffmpeg/movie.rb', line 163 def resolution unless width.nil? or height.nil? "#{width}x#{height}" end end |
#screenshot(output_file, options = EncodingOptions.new, transcoder_options = {}, &block) ⇒ Object
203 204 205 |
# File 'lib/ffmpeg/movie.rb', line 203 def screenshot(output_file, = EncodingOptions.new, = {}, &block) Transcoder.new(self, output_file, .merge(screenshot: true), ).run &block end |
#size ⇒ Object
177 178 179 180 181 182 183 |
# File 'lib/ffmpeg/movie.rb', line 177 def size if local? File.size(@path) else @head.content_length end end |
#transcode(output_file, options = EncodingOptions.new, transcoder_options = {}, &block) ⇒ Object
199 200 201 |
# File 'lib/ffmpeg/movie.rb', line 199 def transcode(output_file, = EncodingOptions.new, = {}, &block) Transcoder.new(self, output_file, , ).run &block end |
#unsupported_streams(std_error) ⇒ Object
134 135 136 137 138 139 140 141 |
# File 'lib/ffmpeg/movie.rb', line 134 def unsupported_streams(std_error) [].tap do |stream_indices| std_error.each_line do |line| match = line.match(UNSUPPORTED_CODEC_PATTERN) stream_indices << match[2].to_i if match end end end |
#valid? ⇒ Boolean
143 144 145 |
# File 'lib/ffmpeg/movie.rb', line 143 def valid? not @invalid end |