Class: FFMPEG::Media
- Inherits:
-
Object
- Object
- FFMPEG::Media
- Defined in:
- lib/ffmpeg/media.rb
Overview
Represents a media file and provides access to its metadata
Instance Attribute Summary collapse
-
#format ⇒ Hash
readonly
Format information.
-
#path ⇒ String
readonly
Path to the media file.
-
#raw ⇒ Hash
readonly
Raw ffprobe output.
-
#streams ⇒ Array<Stream>
readonly
All streams in the media.
Instance Method Summary collapse
-
#audio ⇒ Stream?
Primary audio stream.
-
#audio? ⇒ Boolean
True if media has audio.
-
#audio_bit_rate ⇒ Integer?
Audio bit rate.
-
#audio_channels ⇒ Integer?
Number of audio channels.
-
#audio_codec ⇒ String?
Audio codec name.
-
#audio_streams ⇒ Array<Stream>
All audio streams.
-
#bit_rate ⇒ Integer?
Bit rate in bits/sec.
-
#channel_layout ⇒ String?
Audio channel layout.
-
#creation_time ⇒ Time?
Creation time if available.
-
#detect_scenes(threshold: 0.3) ⇒ Array<Hash>
Detect scene changes in the video.
-
#duration ⇒ Float?
Duration in seconds.
-
#extract_keyframes(output_dir:, interval: nil, count: nil, timestamps: nil) ⇒ Array<String>
Extract keyframes from the video.
-
#format_long_name ⇒ String?
Format long name.
-
#format_name ⇒ String?
Container format name.
-
#frame_count ⇒ Integer?
Approximate total frame count.
-
#frame_rate ⇒ Float?
Video frame rate.
-
#frame_to_timestamp(frame_number) ⇒ Float?
Calculate timestamp for a specific frame.
-
#hd? ⇒ Boolean
True if video is HD (720p+).
-
#height ⇒ Integer?
Video height.
-
#initialize(path) ⇒ Media
constructor
Create a new Media instance.
-
#landscape? ⇒ Boolean
True if video is landscape.
-
#pixel_format ⇒ String?
Pixel format.
-
#portrait? ⇒ Boolean
True if video is portrait.
-
#resolution ⇒ String?
Resolution as “WIDTHxHEIGHT”.
-
#rotation ⇒ Integer?
Video rotation in degrees.
-
#sample_rate ⇒ Integer?
Audio sample rate.
-
#screenshot(timestamp, output_path, resolution: nil) ⇒ String
Take a screenshot at a specific timestamp.
-
#size ⇒ Integer?
File size in bytes.
-
#subtitle_streams ⇒ Array<Stream>
All subtitle streams.
-
#tags ⇒ Hash
Format tags (title, artist, etc.).
-
#timestamp_to_frame(timestamp) ⇒ Integer?
Calculate frame number for a specific timestamp.
-
#title ⇒ String?
Media title from tags.
-
#to_h ⇒ Hash
Serializable representation.
-
#to_s ⇒ String
Human-readable description.
-
#transcode(output_path, **options) {|Float| ... } ⇒ Media
Transcode media to a new file.
-
#uhd? ⇒ Boolean
True if video is 4K (2160p+).
-
#valid? ⇒ Boolean
True if media was successfully parsed.
-
#video ⇒ Stream?
Primary video stream.
-
#video? ⇒ Boolean
True if media has video.
-
#video_bit_rate ⇒ Integer?
Video bit rate.
-
#video_codec ⇒ String?
Video codec name.
-
#video_streams ⇒ Array<Stream>
All video streams.
-
#width ⇒ Integer?
Video width.
Constructor Details
#initialize(path) ⇒ Media
Create a new Media instance
41 42 43 44 45 |
# File 'lib/ffmpeg/media.rb', line 41 def initialize(path) @path = File.(path) validate_file! probe! end |
Instance Attribute Details
#format ⇒ Hash (readonly)
Returns format information.
35 36 37 |
# File 'lib/ffmpeg/media.rb', line 35 def format @format end |
#path ⇒ String (readonly)
Returns path to the media file.
26 27 28 |
# File 'lib/ffmpeg/media.rb', line 26 def path @path end |
#raw ⇒ Hash (readonly)
Returns raw ffprobe output.
29 30 31 |
# File 'lib/ffmpeg/media.rb', line 29 def raw @raw end |
#streams ⇒ Array<Stream> (readonly)
Returns all streams in the media.
32 33 34 |
# File 'lib/ffmpeg/media.rb', line 32 def streams @streams end |
Instance Method Details
#audio ⇒ Stream?
Returns primary audio stream.
118 119 120 |
# File 'lib/ffmpeg/media.rb', line 118 def audio audio_streams.find(&:default) || audio_streams.first end |
#audio? ⇒ Boolean
Returns true if media has audio.
128 129 130 |
# File 'lib/ffmpeg/media.rb', line 128 def audio? audio_streams.any? end |
#audio_bit_rate ⇒ Integer?
Returns audio bit rate.
217 218 219 |
# File 'lib/ffmpeg/media.rb', line 217 def audio_bit_rate audio&.bit_rate end |
#audio_channels ⇒ Integer?
Returns number of audio channels.
207 208 209 |
# File 'lib/ffmpeg/media.rb', line 207 def audio_channels audio&.channels end |
#audio_codec ⇒ String?
Returns audio codec name.
197 198 199 |
# File 'lib/ffmpeg/media.rb', line 197 def audio_codec audio&.codec end |
#audio_streams ⇒ Array<Stream>
Returns all audio streams.
103 104 105 |
# File 'lib/ffmpeg/media.rb', line 103 def audio_streams @audio_streams ||= streams.select(&:audio?) end |
#bit_rate ⇒ Integer?
Returns bit rate in bits/sec.
58 59 60 |
# File 'lib/ffmpeg/media.rb', line 58 def bit_rate format["bit_rate"]&.to_i end |
#channel_layout ⇒ String?
Returns audio channel layout.
212 213 214 |
# File 'lib/ffmpeg/media.rb', line 212 def channel_layout audio&.channel_layout end |
#creation_time ⇒ Time?
Returns creation time if available.
88 89 90 91 92 93 |
# File 'lib/ffmpeg/media.rb', line 88 def creation_time time_str = ["creation_time"] Time.parse(time_str) if time_str rescue ArgumentError nil end |
#detect_scenes(threshold: 0.3) ⇒ Array<Hash>
Detect scene changes in the video
266 267 268 269 |
# File 'lib/ffmpeg/media.rb', line 266 def detect_scenes(threshold: 0.3) detector = SceneDetector.new(self) detector.detect(threshold: threshold) end |
#duration ⇒ Float?
Returns duration in seconds.
53 54 55 |
# File 'lib/ffmpeg/media.rb', line 53 def duration format["duration"]&.to_f end |
#extract_keyframes(output_dir:, interval: nil, count: nil, timestamps: nil) ⇒ Array<String>
Extract keyframes from the video
279 280 281 282 283 284 285 286 287 288 289 |
# File 'lib/ffmpeg/media.rb', line 279 def extract_keyframes(output_dir:, interval: nil, count: nil, timestamps: nil) extractor = KeyframeExtractor.new(self) if extractor.(, output_dir: output_dir) elsif count extractor.extract_count(count, output_dir: output_dir) else extractor.extract_at_intervals(interval: interval || 5.0, output_dir: output_dir) end end |
#format_long_name ⇒ String?
Returns format long name.
73 74 75 |
# File 'lib/ffmpeg/media.rb', line 73 def format_long_name format["format_long_name"] end |
#format_name ⇒ String?
Returns container format name.
68 69 70 |
# File 'lib/ffmpeg/media.rb', line 68 def format_name format["format_name"] end |
#frame_count ⇒ Integer?
Returns approximate total frame count.
224 225 226 227 228 |
# File 'lib/ffmpeg/media.rb', line 224 def frame_count return nil unless duration && frame_rate (duration * frame_rate).round end |
#frame_rate ⇒ Float?
Returns video frame rate.
155 156 157 |
# File 'lib/ffmpeg/media.rb', line 155 def frame_rate video&.frame_rate end |
#frame_to_timestamp(frame_number) ⇒ Float?
Calculate timestamp for a specific frame
233 234 235 236 237 |
# File 'lib/ffmpeg/media.rb', line 233 def (frame_number) return nil unless frame_rate && frame_rate.positive? frame_number.to_f / frame_rate end |
#hd? ⇒ Boolean
Returns true if video is HD (720p+).
185 186 187 |
# File 'lib/ffmpeg/media.rb', line 185 def hd? video&.hd? || false end |
#height ⇒ Integer?
Returns video height.
140 141 142 |
# File 'lib/ffmpeg/media.rb', line 140 def height video&.height end |
#landscape? ⇒ Boolean
Returns true if video is landscape.
180 181 182 |
# File 'lib/ffmpeg/media.rb', line 180 def landscape? video&.landscape? || false end |
#pixel_format ⇒ String?
Returns pixel format.
170 171 172 |
# File 'lib/ffmpeg/media.rb', line 170 def pixel_format video&.pixel_format end |
#portrait? ⇒ Boolean
Returns true if video is portrait.
175 176 177 |
# File 'lib/ffmpeg/media.rb', line 175 def portrait? video&.portrait? || false end |
#resolution ⇒ String?
Returns resolution as “WIDTHxHEIGHT”.
145 146 147 |
# File 'lib/ffmpeg/media.rb', line 145 def resolution video&.resolution end |
#rotation ⇒ Integer?
Returns video rotation in degrees.
165 166 167 |
# File 'lib/ffmpeg/media.rb', line 165 def rotation video&.rotation end |
#sample_rate ⇒ Integer?
Returns audio sample rate.
202 203 204 |
# File 'lib/ffmpeg/media.rb', line 202 def sample_rate audio&.sample_rate end |
#screenshot(timestamp, output_path, resolution: nil) ⇒ String
Take a screenshot at a specific timestamp
298 299 300 301 |
# File 'lib/ffmpeg/media.rb', line 298 def screenshot(, output_path, resolution: nil) extractor = KeyframeExtractor.new(self) extractor.([], output_dir: File.dirname(output_path)).first end |
#size ⇒ Integer?
Returns file size in bytes.
63 64 65 |
# File 'lib/ffmpeg/media.rb', line 63 def size format["size"]&.to_i || File.size(path) end |
#subtitle_streams ⇒ Array<Stream>
Returns all subtitle streams.
108 109 110 |
# File 'lib/ffmpeg/media.rb', line 108 def subtitle_streams @subtitle_streams ||= streams.select(&:subtitle?) end |
#tags ⇒ Hash
Returns format tags (title, artist, etc.).
78 79 80 |
# File 'lib/ffmpeg/media.rb', line 78 def format["tags"] || {} end |
#timestamp_to_frame(timestamp) ⇒ Integer?
Calculate frame number for a specific timestamp
242 243 244 245 246 |
# File 'lib/ffmpeg/media.rb', line 242 def () return nil unless frame_rate (.to_f * frame_rate).round end |
#title ⇒ String?
Returns media title from tags.
83 84 85 |
# File 'lib/ffmpeg/media.rb', line 83 def title ["title"] end |
#to_h ⇒ Hash
Returns serializable representation.
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 |
# File 'lib/ffmpeg/media.rb', line 313 def to_h { path: path, duration: duration, size: size, format: format_name, video: video ? { codec: video_codec, resolution: resolution, frame_rate: frame_rate, bit_rate: video_bit_rate } : nil, audio: audio ? { codec: audio_codec, sample_rate: sample_rate, channels: audio_channels, bit_rate: audio_bit_rate } : nil, streams: streams.map(&:to_s) } end |
#to_s ⇒ String
Returns human-readable description.
304 305 306 307 308 309 310 |
# File 'lib/ffmpeg/media.rb', line 304 def to_s parts = ["Media: #{File.basename(path)}"] parts << "Duration: #{format_duration(duration)}" if duration parts << "Resolution: #{resolution}" if resolution parts << "Codecs: #{video_codec}/#{audio_codec}" if video_codec || audio_codec parts.join(" | ") end |
#transcode(output_path, **options) {|Float| ... } ⇒ Media
Transcode media to a new file
256 257 258 259 |
# File 'lib/ffmpeg/media.rb', line 256 def transcode(output_path, **, &block) transcoder = Transcoder.new(self, output_path, **) transcoder.run(&block) end |
#uhd? ⇒ Boolean
Returns true if video is 4K (2160p+).
190 191 192 |
# File 'lib/ffmpeg/media.rb', line 190 def uhd? video&.uhd? || false end |
#valid? ⇒ Boolean
Returns true if media was successfully parsed.
48 49 50 |
# File 'lib/ffmpeg/media.rb', line 48 def valid? @valid end |
#video ⇒ Stream?
Returns primary video stream.
113 114 115 |
# File 'lib/ffmpeg/media.rb', line 113 def video video_streams.find(&:default) || video_streams.first end |
#video? ⇒ Boolean
Returns true if media has video.
123 124 125 |
# File 'lib/ffmpeg/media.rb', line 123 def video? video_streams.any? end |
#video_bit_rate ⇒ Integer?
Returns video bit rate.
160 161 162 |
# File 'lib/ffmpeg/media.rb', line 160 def video_bit_rate video&.bit_rate end |
#video_codec ⇒ String?
Returns video codec name.
150 151 152 |
# File 'lib/ffmpeg/media.rb', line 150 def video_codec video&.codec end |
#video_streams ⇒ Array<Stream>
Returns all video streams.
98 99 100 |
# File 'lib/ffmpeg/media.rb', line 98 def video_streams @video_streams ||= streams.select(&:video?) end |
#width ⇒ Integer?
Returns video width.
135 136 137 |
# File 'lib/ffmpeg/media.rb', line 135 def width video&.width end |