Skip to content

Commit

Permalink
refact!: rename Movie to Media and add new Stream class
Browse files Browse the repository at this point in the history
  • Loading branch information
bajankristof committed Apr 26, 2024
1 parent 1b9954c commit e9336cd
Show file tree
Hide file tree
Showing 35 changed files with 1,095 additions and 1,399 deletions.
86 changes: 43 additions & 43 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,49 +29,50 @@ require 'ffmpeg', git: 'https://github.com/instructure/ruby-ffmpeg'
### Reading Metadata

```ruby
movie = FFMPEG::Movie.new('path/to/movie.mov')

movie.duration # 7.5 (duration of the movie in seconds)
movie.bitrate # 481 (bitrate in kb/s)
movie.size # 455546 (filesize in bytes)

movie.video_stream # 'h264, yuv420p, 640x480 [PAR 1:1 DAR 4:3], 371 kb/s, 16.75 fps, 15 tbr, 600 tbn, 1200 tbc' (raw video stream info)
movie.video_codec # 'h264'
movie.colorspace # 'yuv420p'
movie.resolution # '640x480'
movie.width # 640 (width of the movie in pixels)
movie.height # 480 (height of the movie in pixels)
movie.frame_rate # 16.72 (frames per second)

movie.audio_stream # 'aac, 44100 Hz, stereo, s16, 75 kb/s' (raw audio stream info)
movie.audio_codec # 'aac'
movie.audio_sample_rate # 44100
movie.audio_channels # 2

media = FFMPEG::Media.new('path/to/movie.mov')

media.duration # 7.5 (duration of the media in seconds)
media.bitrate # 481 (bitrate in kb/s)
media.size # 455546 (filesize in bytes)

media.video_overview # 'h264, yuv420p, 640x480 [PAR 1:1 DAR 4:3], 371 kb/s, 16.75 fps, 15 tbr, 600 tbn, 1200 tbc' (raw video stream info)
media.video_codec_name # 'h264'
media.color_space # 'yuv420p'
media.resolution # '640x480'
media.width # 640 (width of the video stream in pixels)
media.height # 480 (height of the video stream in pixels)
media.frame_rate # 16.72 (frames per second)

media.audio_overview # 'aac, 44100 Hz, stereo, s16, 75 kb/s' (raw audio stream info)
media.audio_codec_name # 'aac'
media.audio_sample_rate # 44100
media.audio_channels # 2

media.video # FFMPEG::Stream
# Multiple audio streams
movie.audio_streams[0] # 'aac, 44100 Hz, stereo, s16, 75 kb/s' (raw audio stream info)
media.audio[0] # FFMPEG::Stream

movie.valid? # true (would be false if ffmpeg fails to read the movie)
media.valid? # true (would be false if ffmpeg fails to read the movie)
```

### Transcoding

First argument is the output file path.

```ruby
movie.transcode('path/to/new_movie.mp4') # Default ffmpeg settings for mp4 format
media.transcode('path/to/new_movie.mp4') # Default ffmpeg settings for mp4 format
```

Keep track of progress with an optional block.

```ruby
movie.transcode('path/to/new_movie.mp4') { |progress| puts progress } # 0.2 ... 0.5 ... 1.0
media.transcode('path/to/new_movie.mp4') { |progress| puts progress } # 0.2 ... 0.5 ... 1.0
```

Give custom command line options with an array.

```ruby
movie.transcode('path/to/new_movie.mp4', %w(-ac aac -vc libx264 -ac 2 ...))
media.transcode('path/to/new_movie.mp4', %w(-ac aac -vc libx264 -ac 2 ...))
```

Use the EncodingOptions parser for humanly readable transcoding options. Below you'll find most of the supported options.
Expand All @@ -86,16 +87,16 @@ options = {
threads: 2, custom: %w(-vf crop=60:60:10:10 -map 0:0 -map 0:1)
}

movie.transcode('movie.mp4', options)
media.transcode('movie.mp4', options)
```

The transcode function returns a Movie object for the encoded file.

```ruby
new_movie = movie.transcode('path/to/new_movie.flv')
new_media = media.transcode('path/to/new_movie.flv')

new_movie.video_codec # 'flv'
new_movie.audio_codec # 'mp3'
new_media.video_codec_name # 'flv'
new_media.audio_codec_name # 'mp3'
```

Aspect ratio is added to encoding options automatically if none is specified.
Expand All @@ -107,31 +108,31 @@ options = { resolution: '320x180' } # Will add -aspect 1.77777777777778 to ffmpe
Preserve aspect ratio on width or height by using the preserve_aspect_ratio transcoder option.

```ruby
movie = FFMPEG::Movie.new('path/to/movie.mov')
media = FFMPEG::Media.new('path/to/movie.mov')

options = { resolution: '320x240' }

kwargs = { preserve_aspect_ratio: :width }
movie.transcode('movie.mp4', options, **kwargs) # Output resolution will be 320x180
media.transcode('movie.mp4', options, **kwargs) # Output resolution will be 320x180

kwargs = { preserve_aspect_ratio: :height }
movie.transcode('movie.mp4', options, **kwargs) # Output resolution will be 426x240
media.transcode('movie.mp4', options, **kwargs) # Output resolution will be 426x240
```

For constant bitrate encoding use video_min_bitrate and video_max_bitrate with buffer_size.

```ruby
options = {video_min_bitrate: 600, video_max_bitrate: 600, buffer_size: 2000}
movie.transcode('path/to/new_movie.flv', options)
media.transcode('path/to/new_movie.flv', options)
```

### Specifying Input Options

To specify which options apply the input, such as changing the input framerate, use `input_options` hash
in the transcoder_options.
in the transcoder kwargs.

```ruby
movie = FFMPEG::Movie.new('path/to/movie.mov')
movie = FFMPEG::Media.new('path/to/movie.mov')

kwargs = { input_options: { framerate: '1/5' } }
movie.transcode('path/to/new_movie.mp4', {}, **kwargs)
Expand Down Expand Up @@ -162,41 +163,40 @@ The watermark will not appear unless `watermark_filter` specifies the position.
You can use the screenshot method to make taking screenshots a bit simpler.

```ruby
movie.screenshot('path/to/new_screenshot.jpg')
media.screenshot('path/to/new_screenshot.jpg')
```

The screenshot method has the very same API as transcode so the same options will work.

```ruby
movie.screenshot('path/to/new_screenshot.bmp', seek_time: 5, resolution: '320x240')
media.screenshot('path/to/new_screenshot.bmp', seek_time: 5, resolution: '320x240')
```

To generate multiple screenshots in a single pass, specify `vframes` and a wildcard filename. Make
sure to disable output file validation. The following code generates up to 20 screenshots every 10 seconds:

```ruby
movie.screenshot('path/to/new_screenshot_%d.jpg', { vframes: 20, frame_rate: '1/6' }, validate: false)
media.screenshot('path/to/new_screenshot_%d.jpg', { vframes: 20, frame_rate: '1/6' }, validate: false)
```

To specify the quality when generating compressed screenshots (.jpg), use `quality` which specifies
ffmpeg `-v:q` option. Quality is an integer between 1 and 31, where lower is better quality:

```ruby
movie.screenshot('path/to/new_screenshot_%d.jpg', quality: 3)
media.screenshot('path/to/new_screenshot_%d.jpg', quality: 3)
```

You can preserve aspect ratio the same way as when using transcode.

```ruby
movie.screenshot('path/to/new_screenshot.png', { seek_time: 2, resolution: '200x120' }, preserve_aspect_ratio: :width)
media.screenshot('path/to/new_screenshot.png', { seek_time: 2, resolution: '200x120' }, preserve_aspect_ratio: :width)
```

### Create a Slideshow from Stills
Creating a slideshow from stills uses named sequences of files and stiches the result together in a slideshow
video.

Since there is not movie to transcode, the Transcoder class needs to be used. The input and input_options are
provided through transcoder options.
Since there is no media to transcode, the Transcoder class needs to be used.

```ruby
slideshow_transcoder = FFMPEG::Transcoder.new(
Expand Down Expand Up @@ -243,12 +243,12 @@ By default Transcoder validates the output file, in case you use FFMPEG for HLS
format that creates multiple outputs you can disable the validation by passing
`validate: false` in the transcoder kwargs.

Note that transcode will not return the encoded movie object in this case since
Note that transcode will not return the encoded media object in this case since
attempting to open a (possibly) invalid output file might result in an error being raised.

```ruby
kwargs = { validate: false }
movie.transcode('movie.mp4', options, **kwargs) # returns nil
media.transcode('movie.mp4', options, **kwargs) # returns nil
```

Copyright
Expand Down
23 changes: 15 additions & 8 deletions lib/ffmpeg.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,22 @@
$LOAD_PATH.unshift File.dirname(__FILE__)

require 'logger'
require 'stringio'

require 'ffmpeg/version'
require 'ffmpeg/errors'
require 'ffmpeg/movie'
require 'ffmpeg/io_monkey'
require 'ffmpeg/transcoder'
require 'ffmpeg/encoding_options'

require_relative 'ffmpeg/version'
require_relative 'ffmpeg/encoding_options'
require_relative 'ffmpeg/errors'
require_relative 'ffmpeg/io'
require_relative 'ffmpeg/media'
require_relative 'ffmpeg/stream'
require_relative 'ffmpeg/transcoder'
require_relative 'ffmpeg/utils'

# The FFMPEG module allows you to customise the behaviour of the FFMPEG library.
#
# @example
# FFMPEG.ffmpeg_binary = '/usr/local/bin/ffmpeg'
# FFMPEG.ffprobe_binary = '/usr/local/bin/ffprobe'
# FFMPEG.logger = Logger.new(STDOUT)
module FFMPEG
# FFMPEG logs information about its progress when it's transcoding.
# Jack in your own logger through this method if you wish to.
Expand Down
2 changes: 2 additions & 0 deletions lib/ffmpeg/encoding_options.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# frozen_string_literal: true

module FFMPEG
# Encoding options for the ffmpeg command
# in the form of a hash.
class EncodingOptions < Hash
def initialize(options = {})
super(nil)
Expand Down
2 changes: 1 addition & 1 deletion lib/ffmpeg/errors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ module FFMPEG
class Error < StandardError
end

class HTTPTooManyRequests < StandardError
class HTTPTooManyRedirects < StandardError
end
end
4 changes: 1 addition & 3 deletions lib/ffmpeg/io_monkey.rb → lib/ffmpeg/io.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@
end
end

#
# Monkey Patch timeout support into the IO class
#
# Monkey Patch timeout support into the IO class...
class IO
def each_with_timeout(pid, seconds, separator = $INPUT_RECORD_SEPARATOR)
last_tick = Time.now
Expand Down
Loading

0 comments on commit e9336cd

Please sign in to comment.