forthebadge forthebadge Gem Version

This gem was last updated on the 07.03.2024 (dd.mm.yyyy notation), at 22:08:18 o'clock.

MultimediaParadise - a toolset project for audio and video related data

The multimedia paradise project bundles together code that can be used for "multimedia data" - in particular for audio and video files.

Most of the functionality found within the multimedia paradise projects depends on the external project called ffmpeg. However had, in principle the code in the toplevel-module called MultimediaParadise should also work with other toolkits as well, provided that said toolkit supports certain actions - such as sox does.

As is often the case, support for other toolkits depends on time investment though - and time availability - of the main author of this project. Nonetheless, whenever possible, support for other toolkits will be added as-is. It is just that ffmpeg is really an excellent project, so other toolkits will have a hard time competing against ffmpeg.

For multimedia-related purposes, ffmpeg can be recommended. Thus, the MultimediaParadise gem will also focus primarily on ffmpeg by default.

A copy of ffmpeg can be obtained from the following URL:

https://www.ffmpeg.org/download.html

Installation of the MultimediaParadise project

There are several ways how to install the multimedia_paradise project. Personally I still use the oldschool way via setup.rb, but the more modern, and recommend way, to install this gem goes via gem install, specifically:

gem install multimedia_paradise --user-install

The reason as to why it is recommended to use the --user-install option is because the various files under the bin/ subdirectory that are part of this gem will be made available in your home directory (under e. g. ~/.gem/ruby/2.5.0/bin or whatever your local ruby version is). That way you can easily add that directory to $PATH or not, and make use of these files if you want to - and if not, just ignore the bin/ subdirectory of this gem altogether.

You can find out the paths used by gem by issuing the following command:

gem environment

Note that even if you can not find such a bin/ subdirectory on your system, these files are distributed within the multimedia_paradise gem itself as such, so just extract the gem, then copy the bin/ files to wherever you want to. There is more than one way to do things!

If you still have a hard time doing so, you can use a toplevel method that will copy all bin/ files into the current working directory. So, for instance, create a directory at the following location:

mkdir /tmp/multimedia_paradise # just an example

Then start irb and issue:

require 'multimedia_paradise'
MultimediaParadise.copy_bin_directory

This will create a directory called bin/ and then proceed to copy all bin/ files that are distributed via the multimedia_paradise gem into that directory. This is just a convenience workaround if --user-dir does not work on your system, for whatever the reason. (Note that this assumes that these bin/ entries are in your HOME directory under bin/ which may not always be the case; I have no idea why this does not work anymore. It used to work in the past. Ask the rubygems maintainers what they broke over the years if this does not work for you. :P But, even in that case, you can just download the .gem file from rubygems.org and extract it on your own, and then you will 100% have the bin/ hierarchy there.)

It is also recommended to install ffmpeg and have it made available on the given computer system at hand - ffmpeg really is a great project, and the multimedia_paradise gem taps into the functionality made available by ffmpeg. In many ways the multimedia_paradise gem is a convenient wrapper over some of ffmpeg's functionality.

In the next subsections on this webpage, several different examples will be shown that may be usable (and useful) by a user, to benefit from the code made available via the MultimediaParadise project. Keep in mind that this project tries to be a helpful toolset project, not necessarily a professional-grade software suite.

Removing the audio from a local video file

Let us begin with a fairly simply use case here: say that you want to remove the audio from a local video file.

So if you have such a use case that requires of you to remove audio from a local video file, use the following API:

require 'multimedia_paradise/audio/remove_audio.rb'
MultimediaParadise.remove_audio(path_to_the_file_goes_in_here)

Specific example for this:

MultimediaParadise.remove_audio('/tmp/foo.avi')
MultimediaParadise.remove_audio('foobar.mp4')

This functionality depends on an installed ffmpeg, as previously pointed out. If anyone happens to know of a pure ruby variant only, let me know - I may add this to the method, as an alternative.

The above method essentially issues the following command:

ffmpeg -i foobar.mp4 -an -vcodec copy /Depot/jj/output_foobar.mp4

So only the video stream is copied, due to the -an option.

Note that the ruby-gtk3 bindings of video_editor.rb, distributed within this project, makes use of this functionality as well.

Note that an executable exists for this functionality as well, at bin/remove_audio. So you can simply issue this on the commandline:

remove_audio foobar.mp4

Streamripper support

There is code support for streamripper, just a tiny wrapper.

This can be invoked like so:

MultimediaParadise.streamripper

This depends on the file streamripper_wrapper.rb which is just a tiny, pure-ruby "wrapper" over streamripper. (It really only directly calls the streampripper binary, so nothing fancy.)

Modifying the timestamps of .srt files

The file srt_regex.rb - situated at multimedia_paradise/video/srt_regex.rb - can be used if you need to batch-modify .srt files, when they have the wrong timestamp, for instance.

This was exactly the reason why I wrote that class a long time ago - some .srt files may have a wrong offset, and so we need to correct them.

Note that this class is quite old and the code quality is not as high as other classes since I wrote it a long time ago. I may improve on it eventually, but for the time being, assume that it isn't one of the best classes in this project. I did not have a use case for .srt files for many years - most of the time I listen to english these days and then I don't even need .srt files. I have had a few videos in chinese (mandarin), and for these .srt files are useful - but even that usage declined, so out of 1000 video files only 3-4 may still be in chinese, so I rarely need to use this class anymore. As a consequence I did not invest much timeo into improving it lateron.

Increasing the volume of an audio file

You can use the toplevel-level method for increasing the volume of an audio file:

MultimediaParadise.increase_volume_of_this_audio_file()

The first argument to this method should be the name of the file that you wish to modify or the name of the files. This is usually a file such as foobar.mp3 or similar.

The second argument is the modified percentage value that is given to -v (and to sox). For example, if you pass in 2.0, then the volume of the audio file at hand will be increased twofold. If it is 3.0, then it will be increased threefold, and so on.

Since the name of the method is "increase_volume", that particular method can not be used to decrease the volume (via negative floats such as -2.0).

Screen capture

If you want to capture the screen, that is, to record what is happening, have a look at the class called MultimediaParadise::CaptureScreen, in the file multimedia_paradise/video/capture_screen.rb.

Autoinclude the main namespace

Since April 2014 you can autoinclude this project's main namespace (toplevel MultimediaParadise constant) by using the following ruby code:

require 'multimedia_paradise/autoinclude'

Using the executable bin/mpa

mpa is a small wrapper over mpv (or mplayer).

It is tailored to my own local videoset, which I store in a yaml file. I am not sure how to best have other people use mpa without the .yml file, but at the worst, it is possible to just use bin/multimedia_paradise to play an existing local video or audio file.

Guessing video names

I use a .yml file to keep track of registered video files.

I also needed a class that tells me the most likely name of a video file, e. g. if the input is "Ninja", then this class should report all Ninja video files, properly sorted, according to the information contained in that .yml file. (This of course requires that this genre is registered in that .yml file.)

class MultimediaParadise::GuessVideoName does precisely that. Input the given search term at hand, such as horror for horror movies, and it should hopefully report some information that may be useful in order to find/name the video file at hand.

Note that this depends on a properly formatted .yml file; and ideally you would create your own .yml file, with your own tags, videos and so forth.

The format of the .yml file should be like this:

a) The number of the video file at hand, as an **Integer** value, such as 1, 2, 3 and so forth.
b) A **hash** that describes at the least the 'title', but may also contain entries such as <b>imdb:</b> and so forth.

Finding local videos

The file find_video.rb can be of help here as it will try to locate local videos.

This is optimized towards my own dataset compiled about videos; in the future, I will most likely provide a way so that other people can also use their own dataset. (The dataset I use is a simple yaml file storing all information about the local videos.)

Delaying the audio of a video-file

FFmpeg allows you to easily delay the audio of a video file.

MultimediaParadise has this included as well, via:

MultimediaParadise.delay_audio()

The first argument to this should be the name of the file that you wish to manipulate, such as foobar.mp4.

The second argument is the amount of seconds for the delay, such as 5.53 seconds.

A new video-file will be generated as a consequence, if all goes well.

Denoising audio/video

This subsection is about removing noise from a multimedia file.

Noise in this context refers to unwanted audio, such as scratching on a blackboard during a university lecture, and similar unwanted noises.

First, this functionality was needed because I inherited audio recordings that were made via a cheap mp3-recorder from like +10 years ago or so, say, the year 2009 - something like that.

The human voice has a frequency range between 300Hz - 3000Hz.

The noise in these files was extremey disturbing and distracting, and I wanted to get rid of it, in order to more easily hear the voice of the speaker. This also included increasing the volume as well, but that is for another subsection.

The subsection here will additionally report some of my findings from back then - as a memo.

A simple filter-strategy is to first apply highpass, and then lowpass, via ffmpeg, such as in this way:

ffmpeg -i foobar.mp3 -af "lowpass=f=3000, highpass=f=200" output.mp3

Your local file comes first, such as the file foobar.mp3. This should remove some of the noise that you may find in a recording, but you may have to tweak the values a little in order to get the most out of it.

Note that you can use ffplay to see the effect of this:

ffplay INPUT_FILE -af lowpass=3000,highpass=200
ffplay foobar.mp3 -af lowpass=4000,highpass=200
ffplay foobar.mp3 -af lowpass=2000,highpass=200

I integrated this functionality into MultimediaParadise, via the following simple API:

MultimediaParadise.denoise('foobar.mp3')

This is the default use case, by just supplying the name/path to the audio file in question.

The second argument to this method is the lowpass value; the third argument is for the highpass value:

MultimediaParadise.denoise('foobar.mp3', '250', '2000')

This, surprisingly enough, worked. But I do not think it is the ideal value.

For more information, see the following blog entry from 2017:

https://manerosss.wordpress.com/2017/07/24/ffmpeg-%C2%B7-apply-a-filter-to-enhance-voice-by-removing-low-and-high-frequency-noises/

If you need to find out which values are best, you can use ffplay such as in this way:

ffplay INPUT -af lowpass=3000,highpass=200

Creating a screencast with multimedia_paradise and FFMPEG

Code in the file multimedia_paradise/toplevel_methods/screencast.rb can be used to record a screencast (on Linux).

The API is as follows:

MultimediaParadise.start_screencast

The method accepts several parameters - if you need fine tuning then have a look at that file.

Presently only video without audio can be recorded, but there are tutorials out there that enable recording of audio as well. I will have a look into this at a later time (<- written in September 2018).

Query the audio codec of a video file

You can use this top-level API to determine the audio codec of a video file:

MultimediaParadise.query_the_audio_codec_of_this_file()
MultimediaParadise.query_the_audio_codec()
MultimediaParadise.audio_codec?()

All variants listed above work; the last option is the shortest one, apparently.

The argument should be the path to a locally existing videofile.

Say that your file is at /Depot/foobar.avi then the ruby code may look like this:

require 'multimedia_paradise'
uses_this_codec = MultimediaParadise.audio_codec?('/Depot/foobar.avi') # => ["aac"]

Note that this functionality depends on ffmpeg right now, so make sure to install ffmpeg first.

Converting into .mp3 format

You can use class MultimediaParadise::Audio::ToMp3 to convert e. g. a .wav file into a .mp3 file:

MultimediaParadise::Audio::ToMp3.new('path_to_wav.waf')

As this may be a bit cumbersome to type, there exists a simpler top-level method to convert an audio-file into the .mp3 format:

MultimediaParadise.to_mp3(*input_files_here)
MultimediaParadise.to_mp3( %( foo.wav bar.wav ) )

ffmpeg options

This subsection just shows a few options for ffmpeg; I added this mostly because I tend to be quite forgetful. That way I can have a quick overview on the homepage of this gem here.

Commandline flag Example Implementation Status
-s -s 500×500 convert the video into a width x height ratio, of 500 x 500 pixel
-vcodec -vcodec mpeg4 specify which video-codec is to be used, e. g. for the conversion of a video file

Playing several multimedia-files from a list/file

You can pass a list of files that the MultimediaParadise project should play.

The toplevel method is MultimediaParadise.play_this_list(), so for example:

MultimediaParadise.play_this_list '

  /Users/x/VIDEO/Cartoons/Simpsons-09/Treehouse_Of_Horror_VIII.m4v
  /Users/x/VIDEO/Cartoons/Simpsons-09/The_Joy_Of_Sect.m4v
  /Users/x/VIDEO/Cartoons/Simpsons-08/The_Springfield_Files.m4v

'

Empty lines will be ignored, so the method will only play these entries if they are not empty.

The alias MultimediaParadise.play_from_this_list() would also work, by the way.

I needed this functionality because sometimes other classes written in ruby may show, on the commandline, such a flat list, via a long String broken by newlines.

Environment variables for the MultimediaParadise project

The MultimediaParadise project is tailored to my own needs primarily, which means that other people may not necessarily benefit from the project as much. Additionally, as of December 2018, there are some hardcoded paths, which makes this even worse. I have decided in December 2018 that this approach will change in the future.

For the time being, you can use certain ENV (environment) flags to specify where your audio/video files are kept. This assumes that you have one central directory for these files; respectively up to two, if you keep your audio and video files separate.

For specifying where your local video files reside, you can use the constant called MULTIMEDIA_PARADISE_DEPOT_VIDEO. Simply set this, in your shell, to be the path to the directory where your video files may be, such as in:

export MULTIMEDIA_PARADISE_DEPOT_VIDEO=/opt/videos

A similar constant exists for audio files; simply set MULTIMEDIA_PARADISE_DEPOT_AUDIO.

export MULTIMEDIA_PARADISE_DEPOT_AUDIO=/opt/my_songs

Genre support of video files

If you have a .yml file that keeps your video files sorted, then you can also use a genre: tag identifier to classify the video at hand.

For example, the movie The Blade Runner may have an associated genre called Science Fiction. The movie Poltergeist may have a genre tag called Horror and so on.

Once the genre-tagging has been done, we can search for these genres on the commandline, via class VideoGenres.

See its --help option for commands.

video_genres --help

If you wish to find out which science fiction movies are registered, do:

video_genres --genre="Science Fiction"

You can also use a shorter variant, via a Pseudo-Regex:

video_genres "/Science Fiction/"

Or the horror genre:

video_genres "/Horror/"

The "" can be omitted it seems (tested this on July 2021):

video_genres /Horror/

Some shortcuts exist if the above is too cumbersome. For example, all science fiction movies could also be shown via this way:

video_genres --science-fiction

To see the available video genres, do this:

video_genres --available-video-genres

It you want to play a random horror movie, provided that you have these registered tags, you can do the following:

video_genres --play-random-video-from-this-genre=horror

Keep in mind that this depends on the information stored in the file video_collection.yml. This is catering to my own use case, so you may want to populate this with your own dataset.

Copying and merging the same video

If you sort of wish to "duplicate" a video, but append this onto an existing one, then you can use this method:

MultimediaParadise.copy_and_merge_this_video_n_times

The first argument should be the existing video file; the second argument should be how many times it should be "repeated", which should be a number. For example, the number 5 means that the video will be merged onto itself 4 times, thus creating a video that is 5x the length (all with the same content).

There are alternatives to this, such as looping the same video; but I wanted to really be able to have the same video be played over and over again, even though this made the size larger.

MultimediaParadise::AnalyseMultimediaFile

class MultimediaParadise::AnalyseMultimediaFile can be used to analyse multimedia files (e. g. audio and video files), on the commandline.

I needed this because ffmpeg -i alone was tiresome to read.

Flipping and rotating video files

FFMpeg can easily flip video files. MultimediaParadise supports this functionality too, through the file multimedia_paradise/toplevel_methods/flip_and_rotate.rb.

Horizontal and vertical flipping is supported through these two toplevel APIs:

MultimediaParadise.horizontal_flip()
MultimediaParadise.vertical_flip()

The latter variant also has a simpler, more intuitive API:

MultimediaParadise.flip_upside_down()

So essentially, you picture a video, and then simply flip the top to the bottom, and the bottom to the top. Easy-peasy.

The first argument to this method should be the name/path to an existing video file.

You can also rotate a video file by 90° via this API:

MultimediaParadise.rotate_this_video_file_by_90_degrees('foo.mpg')

Since as of March 2019, two more methods were added to flip a video (rotate a video) clockwise and counter-clockwise, by 90° each:

MultimediaParadise.flip_video_to_the_right
MultimediaParadise.flip_video_to_the_left

So the older method MultimediaParadise.rotate_this_video_file_by_90_degrees() is essentially the same as the newer method MultimediaParadise.flip_video_to_the_right.

Merging audio files together

class MultimediaParadise::MergeAudioFiles can be used to merge different audio files together. If no specific input argument is provided then this class will scan for all audio files in the current working directory and all subdirectories, then merge these together into a new file called output.mp3.

I needed this functionality so that I could put lectures together into a single file - made it easier to listen to a single file, rather than find them all spread out.

Toplevel cutting multimedia files

This subsection deals with cutting multimedia files, that is, to chop a longer file into one (or several) smaller files.

The primary method for this is called MultimediaParadise.cut_from_to(), but you can also use a few aliases to this method, such as MultimediaParadise.cut().

The API is flexible.

Let's first show a few examples:

MultimediaParadise.cut_from_to('00:00:01-00:25:10', this_file: 'Tales_from_the_crypt_S05E10_Came_the_Dawn_1993.mp4')
MultimediaParadise.cut_from_to('00:02:23 / 00:28:04', this_file: 'Tales_from_the_crypt_S05E10_Came_the_Dawn_1993.mp4')
MultimediaParadise.cut(to: '00:22:50', this_file: 'TALES_FROM_THE_CRYPT/Tales_from_the_crypt_S06E11_Surprise_Party.mkv')

These are somewhat equivalent.

The simplest way may be to pass, as first argument, a String to the method, denoting the start position and the end position, in HH:MM:SS format. But you can also decide to use a Hash instead, such as the third example shows.

Do note that if you decide to use a String, you can either use the '-' variant or a ' / ' variant. The latter is the default display format for the mpv video/audio player, so I added support for it since copy/pasting may be a bit simpler that way.

The special key called :this_file should be the file that you wish to cut. The absolute path should be given here; for my home system I also use some fake-macros, such as TALES_FROM_THE_CRYPT/ to denote where tales from the crypt may reside (and other files). This allows me to more easily make use of my local file system.

The key :to refers to the end position, that is, when to make the cut.

The ideal scenario for this method is to simply cut from a start position to an end position - in other words, to make an existing video file shorter.

Do note that another class, called CutAudio, also exists as part of the multimedia_paradise project. This is partially due to legacy reasons; and partially due to CutAudio being primarily used for .mp3 files, and for interactive use. One day the functionality may be re-used, but for the time being I will keep it separate (less work for now).

If you rather want a simple API, where you input only two Strings usually (as parameters), then you could use:

MultimediaParadise.video_duration(of_this_file, '00:30:00-00:35:00')

The first argument would be the file that you wish to cut; and the second is the duration, so two Strings in total. Interally this will be passed to the method MultimediaParadise.cut_from_to() anyway, so you could even use a Hash instead - but the primary use case for that method is to allow for a simpler API. Use whatever you prefer.

Resizing a video

ffmpeg makes it easy to resize a video.

For example, say that you wish to re-scale an existing video to the same ratio, but with fewer pixels, like 640. You could use the following commandline invocation, with the -vf flag, for this task:

ffmpeg -i input.mp4 -vf scale=640:-1 output.mp4

In this case, output.mp4 will have 640 pixels in width.

The strange -1 is simply a way to tell ffmpeg that the same aspect ratio should be kept. That way ffmpeg will calculate which ratio value should be used, in order to retain the original width:height relation. You can sometimes see that people use the wrong aspect ratio, and then their video may look distorted.

MultimediaParadise also supports this via:

MultimediaParadise.scale_this_video()
MultimediaParadise.resize_this_vide()

The first argument is the path to the local input-file, such as *input.mp4.

After that a Hash can be used, where height and width can be given.

MultimediaParadise.scale_this_video('input.mp4', height: 320, width: 220)

The argument for :width can be omitted, in which case -1 will be used as default:

MultimediaParadise.scale_this_video('input.mp4', height: 320)

Would be the same as:

MultimediaParadise.scale_this_video('input.mp4', height: 320, height: -1)

The value for height: can be ignored too, in which case it will default to 640 - but this default value may change one day in the future, so it may be better to specify at the least one value here. But, ultimately, if you don't care, this could also work:

MultimediaParadise.scale_this_video('input.mp4')

We may even omit the first argument in the future, one day, if we assign a default file on the toplevel - but for the time being (September 2019), the API is how it is and requires at the least one argument.

Creating a video out of an audio file, such as a .mp3 file

Via the API MultimediaParadise.create_video_from_this_audio() you can "create" a video, from an audio file, such as a .mp3 file.

This requires a static image, which is the second argument to that method.

Why did I add this method? I needed a way to upload .mp3 files to a remote website but they had a filter removing .mp3 files; they allowed for .mp4 files, so I converted it into a .mp4 file and that works. That is strange, since you can always use ffmpeg to extract the .mp3 audio again - so I dont understand the filter that prevents .mp3 upload but allows .mp4 upload ...

Quite odd if you ask me.

*:\*

:/

Anyway - here an example for the official API for this, from within ruby:

this_audio_file = 'foobar.mp3'
this_image_file = '/FORENSIC_CAT.jpg'
MultimediaParadise.create_video_from_this_audio(this_audio_file, this_image_file)

MovieSearcher

class MovieSearcher can be used to look up information about a movie from http://www.omdbapi.com, if you have an API key.

The code written for this class is not great, but if all you need is some quick commandline information then this class could be used. It can be found at multimedia_paradise/video/movie_searcher.rb.

Since as of 02.01.2020, an executable is now distributed as well, called movie_searcher (under the bin subdirectory of this gem).

I have aliased this executable to videorating, and then simply do this on the commandline:

videorating tremors

You may need an API key called OMDBAPI_API_KEY. I recommend you to set this; class MovieSearch will then try to pick it up when it was set (see the ruby code for this).

Deshaking videos

Ffmpeg has support for deshaking videos through a filter:

https://ffmpeg.org/ffmpeg-filters.html#deshake

The deshake-filter from ffmpeg helps remove camera shake from hand-holding a camera.

The API for multimedia_paradise is the following:

MultimediaParadise.deshake(input_files_go_here)
MultimediaParadise.deshake('foobar.mp4')

Missing video files

Via:

mpa --missing-videos?

I can determine which video files are missing locally.

This is evidently catered to my own use case, and a big .yml file that I maintain. You may have to create your own .yml file here if you wish to make use of this functionality.

class ConvertAudioToVideoWithImage

class ConvertAudioToVideoWithImage allows you to "attach" a static image file to an audio file, such as a .mp3 file.

This functionality depends on ffmpeg, so you need to have ffmpeg available in order to make use of this class.

Two arguments are necessary to class ConvertAudioToVideoWithImage:

(1) first, the audio-file
(2) second, the image file that you wish to use

You can also use the following toplevel-method:

MultimediaParadise.to_avi_with_this_image()

with the same parameter pattern.

To give you a specific example - say that you have your .mp3 file at:

/Depot/j/foobar.mp3

And your image at:

/Depot/Images/foobar.png

Then the proper way to use the toplevel-method would be:

MultimediaParadise.to_avi_with_this_image('/Depot/j/foobar.mp3','/Depot/Images/foobar.png')

It does not have to be an .avi file though. You can also use a .mp4 file via:

MultimediaParadise.to_mp4_with_this_image('foo.mp3','bar.png')

The latter method can also be used from the commandline via:

convert_audio_to_mp4video_with_image a.mp3 b.png

Remember that the audio file comes first, and the image file comes last.

Removing the last second of an audio file

If you just need to quickly chop off the last 1 second from an audio file then you can use this API:

MultimediaParadise::RemoveLastSecond.new(ARGV)
MultimediaParadise::RemoveLastSecond.new('foobar.mp3')

Encoding a video via MultimediaParadise

You can use the toplevel method called MultimediaParadise.encode_this_video() to encode a video.

By default CRF will be used, which is the Constant Rate Factor.

Support for two-pass encoding has not been added to MultimediParadise, but you can read up on ffmpeg how to do this:

https://trac.ffmpeg.org/wiki/Encode/H.264

Example:

require 'multimedia_paradise/toplevel_methods/encode_this_video.rb'
MultimediaParadise.encode_this_video('foobar.avi')

The default output for this will be .mkv, which is the matroska container. (Currently that method in MultimediaParadise does not allow for another output format, in June 2020; but this may be changed in the future in another release of this project.)

MultimediaParadise.set_player_in_use()

The toplevel method MultimediaParadise.set_player_in_use() can be used to set the main multimedia player (audio + video) in use for the MultimediaProject. Normally I set this to mplayer or mpv, but vlc or any other player could also be used here.

You can also quickly set to use mpv since as of the 30th June 2020.

Usage example for permanently setting this:

multimedia_paradise --use-mpv

This will modify the content of a .yml file.

The file video_collection.yml

The file video_collection.yml, which is distributed by this project, can be used to denote different videos files.

This is catered to my own use case, but you can adapt this file to your own use case.

I use the file to automatically handle local videos, such as batch-renaming or ensuring that everything is correct, and so on.

To determine the default (assumed) location, try this method:

MultimediaParadise.file_video_collection

Working with subtitles

You can embed subtitles into a video directly. This subsection explains how this can be done.

Embedding subtitles (text files such as .srt files) into a video file is trivial with ffmpeg. The multimedia_paradise project supports this as well, via the following toplevel API:

require 'multimedia_paradise/toplevel_methods/subtitles.rb'
MultimediaParadise.embed_this_subtitle_onto_that_video('foo.srt','bar.avi')

If you wish to remove a subtitle from a video file, try this:

MultimediaParadise.remove_subtitles_from_this_video_file('foobar.mp4')

Since as of October 2020, a file called bin/remove_subtitles is made available as well, for commandline usage.

Additional documentation and information

In October 2020 I decided to publish all my collected local video and audio related content, which is made available through oldschool .cgi files. To make this even more complicated, most of these files are written in german so these have only a limited use for most people. Still, I think some of the information contained therein may be useful for other people, which is why I will publish this slowly over the coming months. Furthermore, some yaml-files are part of this, and publishing yaml files is useful, as it is decoupled from the programming language (in this case ruby).

Changing the audio codec of a video file via FFMpeg

If you want to change the audio codec in a given video file, say, foobar.avi, then you can use this API:

MultimediaParadise.use_lame_codec('foobar.avi')

This essentially just combines -vcodec copy -acodec libmp3lame but I wanted to have a simpler top-level API in ruby for this too, so this method was added.

Playing a random (video or audio) file

class MultimediaParadise::PlayRandomFile can play a random multimedia file. Since this will select a file randomly, you can only pass in a directory for now - although passing in an Array may also make sense, so perhaps this class will be extended at a later time.

Copying a random video file

If you ever need to copy a random video file to the current working directory then the following class may be of help here:

require 'multimedia_paradise/video/copy_random_video.rb'
MultimediaParadise::CopyRandomVideo.new(ARGV)

Unfortunately this is currently hardcoded to my own home setup. In the future (past January 2021) I may make this more flexible, but it was mostly a "throwaway" script, so I just moved on after having written it.

Bugs in the MultimediaParadise project

Bugs are annoying - let's get rid of them!

If you run into a bug, or a usability problem, feel free to report it. Email should suffice for now; at some point I will add github issue trackers again, but I am not really using git, so this makes this a bit awkward. :)

If you can, please provide information how to reproduce a given bug. The easier it is to reproduce it, the easier it should be to fix it.

Autogenerate music

I will expand this subsection in the coming months and years. The goal is to be able to autogenerate at the least some music. I am not interested in perfect concertos, but some simple beats that could be combined.

Thanks to ffmpeg we can easily modify the metadata entry of a .mp3 file.

MultimediaParadise supports this too, via the following API:

MultimediaParadise.set_title_of(this_audio_file, this_title)

So, the first argument should be the local path to the multimedia file, such as a .mp3 file; and the second argument should be the title that this file should have. I use this for batch-setting the title - and a file called bin/auto_title exists that does this from the commandline as well.

In plain ffmpeg command, it would look like this:

ffmpeg -i input.mp4 -metadata title="The video title" -c copy output.mp4

The title comes into the title="" entry there.

For .mp4 files, but possibly also .mp4 files, you could use the following meta-data tags:

 - title
 - author
 - album_artist
 - album
 - grouping
 - composer
 - year
 - track
 - comment
 - genre
 - copyright
 - description
 - synopsis
 - show
 - episode_id
 - network
 - lyrics

Obtaining an image from a video file via ffmpeg

You can use this commandline variant to obtain one image from a video file. Via -ss you can specify the start position.

Usage example:

ffmpeg -i input.mp4 -vframes 1 -an -s 320x180 -y -ss 12 output.jpg 

The multimedia_paradise gem makes this possible via this API:

MultimediaParadise.return_image_from_this_video_file(
  'input.mp4',
  starting_position = 12, # in n seconds
  width_and_height_for_the_image = '480x270'
)

The path to the local video file should come as the first argument to this method.

The sinatra interface of the MultimediaParadise project

First install sinatra:

gem install sinatra # or use --user-install

Next you should be able to start it, either via MultimediaParadise.start_sinatra or from the commandline via:

multimedia_paradise --sinatra

You should then be presented with the sinatra-interface.

For example, to determine how many local videos are available, use n_local_videos, as in:

http://localhost:5580/n_local_videos

This is also available via the index, so you just have to click on it via the mouse button.

You can view all registered video files, aka their respective names, via:

http://localhost:5580/available_video_files

You can also directly play video files, if they are available (at the least on my home setup) via:

http://localhost:5580/027

Or just the name. This requires that the base directory where the video file resides, is added to the sinatra application. And, of course, that the video file also exists at that path. If it does not work on your system, make sure that the correct directory is passed in, and that the video file exists locally; have a look at the sinatra-specific code in multimedia_paradise/sinatra/. The default is for my home system so you may have to change a very few lines.

You can also pass the name of the video file directly and if it exists in the specified directory it will be played.

I tested this on windows as well, and it works there - at the least for .mp4 files. I could not get .avi files to work yet, neither on windows nor on linux. I am not entirely certain as to why, but perhaps it may be time to ditch .avi files altogether, in favour of .mp4.

I also intend to add a play/ API just to keep this a bit separate and visually nicer.

Unfortunately I have been hitting some problems with sinatra, namely that I have no idea what is going on "behind the scenes". I'll have to re-evaluate this at a later time - mostly trying to find a replacement that is more debug-friendly than sinatra, without being as bloated as ruby on rails.

In June 2022 I tested this on windows, such as via an URL to a local video file like:

http://localhost:5580/035_Back_to_the_Future.mp4

And it worked! \o/

The .mp4 file was playing in the browser. I guess this will favour the .mp4 file format versus .mkv or .avi, simply because it gives us one more option to play video files. I did get .mkv to work in the browser, though, so perhaps only .avi is the one that will have to be deprecated.

It goes slower than on Linux, though, so Linux is really the better operating system, in my opinion.

Lyrics of songs

This subsection is just a little reminder for myself.

I searched for translations of different lyrics on the www. However had, many of the translations are clearly wrong, where the words are incorrect. In theory this may be because whoever made the translation manually simply misheard the word(s) - but often the words are so different that this can not be explained by a genuine mistake, in my opinion. I think many of these translations are deliberately incorrect, simply because the words are too different. This problem is then amplified by different websites copy/pasting the same error.

I give you a specific example.

During the eurodance era, there was one interesting rapper in the group Sonic Surfers, with the song called Don't give it up.

One passage is 'officially' this:

Tap into my brain and just channelin'
Let's get high on bass and trebelin'

However had, I listened to this part about ten times now and in my opinion the text is the following:

Tap into my brain and just channelin'
Let's get high on base and adrenaline

I am almost 100% certain that he said "base" and "adrenaline". It also makes more sense - adrenaline is more logical than trebeling, whatever that should even be. So why was the translation that is available on the www different? Yes, it may be a sloppy mistake, I understand that, but ... to mistake two words that are quite clearly different? And that is not the only example.

In the same text of the song you have this passage:

If anybody should be trippin' as you do
Dance into the trance on my little kavoodoo

But my own translation is this:

If anybody should be trippin' as you do
Dance into the trance on my lyrical voodoo

Again - I could be wrong, but ... not sure. Lyrical voodoo makes more sense than does "little kavoodoo" too.

Anyway. You can find many similar examples in different songs. I do not think these are ALL accidents; I think the translations are, at the least to some extent, deliberately incorrect. You could reason - or assume - that this came automated by scripts/robots, but the errors seem so subtly incorrect that I have a hard time imagining this did not come by some random underpaid person in India or what not, working for a low wage ... so there may be a non-deliberate accident explanation, but still. It is clearly not correct either way how you look at it, for whatever the underlying reason for this may be. (Since as of 2023 I have amended my opinion a little bit - this could actually have come from some AI-specific tool, such as ChatGPT or what not. I am no longer certain this came from a human, despite the seemingly non-randomness of the editing. This could be explained if a script was not making changes ALL of the time but included some more context from elsewhere.)

Evidently this is fairly pointless for other people to know, but since I actually want to understand the lyrics of good songs I thought I should note this down, for future reference. My larger theory is that many - or most - of these translations were created not by human beings but by a script (perhaps not the above example, but many others). And that script was, possibly, altered to include deliberately incorrect words near the end. That would explain the pattern I could see above, where the first sentence is correct, the second sentence becomes incorrect towards the end. It could just be a human too, though - not possible to distinguish this.

(Of course a human being could also do this, e. g. if paid to do this and then consistently apply that pattern, or indeed doing genuine mistakes. It's not possible to easily distinguish between a script, or human beings that work consistently in doing incorrect translations. But a script runs for virtually free, whereas human beings cost money, so I assume the more likely explanation is that this is done by one, or several, script(s). Would be interesting to find out WHO is doing these translations on different websites. Some evidently only copy/paste, because you can find the exact same error in the "translated" websites as well.)

I do not have enough statistical data to verify either way, but I am quite suspicious about what is presented to me nowadays via Google in general - I happily admit that I no longer trust Google, so I will simply assume that many of these translations (but not all) did not come from human beings, but from software instead. You can also find websites that aggregate other resources, and the randomly munch it together in ways that makes no real sense. So much fake stuff going on these days ...

Adding silence to an audio file

If you want to append 5 seconds of silence to a song, you can do so via sox, and the following API in the MultimediaParadise toplevel namespace:

MultimediaParadise.append_silence_to_this_song(5, 'ack.mp3')

(The file size of the new song will be fairly large, though. I am not certain as to why that is the case. Seems awkward that silence leads to a massively increased file size ... anyone knows how to do that via ffmpeg?)

CutMultimedia - a merger of CutAudio and CutVideo

Many years ago I had a class called CutAudio. I even received an email concerning this class (which was made available as a standalone .gem on rubygems.org, back then), from a user who reported several bugs with it - and a lack of documentation. All of which was correct back then. :-)

In February 2021 I finally started to rewrite the important parts of the old class called CutAudio into CutMultimedia, while also adding more documentation to it. This is presently still an ongoing endeavour, so ... stay-tuned in this regard!

Another goal for this rewrite was to add ruby-gtk3 bindings to it from the get go. That way users who do not like the commandline are able to use this class as well, if they have ruby-gtk3 available. The primary focus, nonetheless, is on the commandline use, though, and not everything that is available on the commandline is available via the GUI. The GUI mostly only captures the essential parts, whereas the commandline exposes more functionality that is less commonly required.

The idea behind class CutMultimedia is that no matter whether you use a video file or an audio file as input to this class, to allow you to easily and quickly cut this audio file (or video file), and re-join these new audio files easily as well into a single file. So it is not only cutting alone; it also means to make use of re-joining. The end product is then a new file, such as a new .mp3 file. The interactive part that is made available via the menu() method exists primarily to facilitate that goal: to cut an existing .mp3 file and rejoin the desired segments into a new .mp3 file.

The name for the class is now CutMultimedia, but a backwards alias exists, called CutAudio. For consistency reasons, CutVideo also exists. I recommend to use the name CutMultimedia directly, though - that name should be more 'durable' than the other two names.

You can find the code for this class here, in the following subdirectory:

require 'multimedia_paradise/multimedia/cut_multimedia/*.rb'

The class can be invoked by either of the following executables, residing under the bin/ hierarchy:

bin/cut_audio
bin/cut_video
bin/cut_multimedia # this one is probably the best variant

Simply have a look at the file content if you have a hard time finding it on your file system; something changed in rubygems so I don't know where files are placed anymore, but these bin/ files are part of the .gem, so simply extract the gem and have a look around.

As first argument to this class you should that you wish to modify.

For example, if you have a file available at the location /tmp/foobar.mp3 then you could invoke cut_audio like so:

bin/cut_audio /tmp/foobar.mp3
cut_audio /tmp/foobar.mp3
caudio /tmp/foobar.mp3 # I actually use an alias called 'caudio'; faster and easier for me to type.

Or use cut_multimedia as a name instead - that is equivalent since as of February 2021.

You can avoid the leading bin/ part if the file at hand is in your PATH variable. Or if you set an alias, anyway.

(As said Ialiased it to "caudio", as that is my mnemonic for "cut-audio".)

When you apply the above command, on the commandline, you will enter the interactive menu interface (if that file was found). This interface allows you to do certain actions that can be helpful in regards to cutting audio or video files.

For example, specifying start and end position of the cutting job, which is one of the most commonly commands I use. See some examples for this a bit below.

You can also ask for "help" via:

help

while you are in the interactive mode.

You can use the ruby-gtk3 interface, which is under multimedia_paradise/gui/gtk3/cut_multimedia/.

You can designate start and stop positions when in interactive mode of class CutMultimedia. You can do so via prefixing "s" and suffixing "e", such as in the following way:

s10 # start at 10 seconds
e20 # end at 20 seconds

This would mean to "start at 10 seconds" and "end at 20 seconds". So we will here cut out the intermediate 10 seconds between these two points.

If you want the commands to be more verbose, try these longer variants instead:

start10
end20

But I prefer "s" and "e" - less to type.

There is some support for specifying both start and end positions in one go. For example, the above commands shown so far require two lines to be used, e. g. first s10 and then e20. You can simplify this to the following one-liner instead:

10-20
10 - 20 # this is also possible, if you want it more spaced out

That way you can skip using the "s" and "e" altogether and it should work just fine. If it does not, it is most likely a bug - feel free to send an email to point out a bug, or something missing in regards to the documentation and it will be addressed eventually.

Via "play" you can play the audio file at hand; I recommend having installed mplayer or mpv for this task. That way you can find out where you may wish to cut in the first place. I use this quickly to determine the exact positions, on the commandline, and then continue to define start and end positions.

Once you have all your start and end positions defined, you can run the following command to commit:

cut

This will cut out the selected subsection; in this case the part from 10 seconds to 20 seconds. You will then have a new .mp3 file that should be about 10 seconds long (ffmpeg does not seem to cut at 100% precision all the time; recently it created a file with a duration of 10.03 seconds rather than 10.00 seconds. I do not know why, so I can not explain this behaviour.)

The number in use there specifies how many seconds are to be used. This can sometimes be a bit difficult to calculate in your head e. g. how many seconds do 83 minutes entail to. How many of you can quickly calculate this accurately in your head? I struggle there.

So, a 'pseudo-calculator' can be used and queried from within class CutMultimedia.

For example, if you input the following:

6*60

Then this would quickly show you that the result of this is 360 seconds (the input meant 6 minutes, if you think about it - aka 6 * 60 seconds, as one minute has 60 seconds).

There are many more options available, so have a look at the "help" section there. Keep in mind that CutMultimedia is a bit complicated to use sometimes, and also has had a very few bugs as well. On the other hand, if you focus on the three main actions (start, end, cut) then this is really quite simply to use. You'll get the hang of it quickly.

Take note that the ruby-gtk3 bindings to class CutMultimedia are not perfect, and they are not complete, either. I may improve on them in the future, but for now they have to suffice. (My main goal is to actually clone the functionality of mp3directcut, but I don't know how to run a visualize-function so ... that's on my todo list.)

Note that you can start the ruby-gtk3 bindings from the interactive menu via:

gui

In October 2021 code was added to use this in a scripted fashion. So, rather than define the start and end positions interactively, you can now input them into a text file instead.

The format of this text file should look like this:

start 2
end 4
start 6
end 8

s 10.5
e 12.5

So, alternating between start_position and end_position. That's it.

You can use "start" or "s", or "end" or "e", respectively. But either of which is mandatory; omitting both s and e is not possible.

Furthermore you need to use a "clean" workspace, aka only the file that you wish to modify, such as foobar.mp3 in the given directory.

The code for this functionality is available in the following API:

MultimediaParadise::CutMultimedia.evaluate_from_this_file()

Pass, as argument to it, the file that contains these short and end positions, e. g. the text file that you will use. The code will then automatically pick up the first .mp3 file that it can find in the current directory, so again, use a clean workspace for this step.

Then it will do the specified actions and merge the newly created files back in. (There is also an additional step to convert to .wav and back to .mp3. The reason for this is that somehow ffmpeg's concat feature does not fix the broken headers. I don't know how else to fix this other than re-encoding. If someone else has a better solution I will be happy to hear it.)

If the file was generated (aka merged) then all other files used in the process will be removed. So if all goes well, you will have +1 file in that directory: the cutted file.

Note that while CutMultimedia, originally called CutAudio, was started to cut .mp3 files, you can also modify other files with it too, such as merging/cutting .waf files, .ogg files, .aac files, .aiff files and so forth. The only requirement is that ffmpeg can handle these files.

In October 2023 class CutMultimedia was improved a bit. It is now possible to only specify an end position, via:

-00:28:49

This will (automatically) designate the start position at 0.

Overlaying two audio songs

Use:

MultimediaParadise.overlay_two_audio_files()
MultimediaParadise.overlay_two_audio_files('foo.mp3','bar.mp3')

This depends on sox. It is possible to do so via ffmpeg but the syntax is very complex, so I opted for sox for now. In the future this may be improved, but for now this has to suffice.

mp3 tags

This short subsection contains just a bit of information concerning mp3 ID tags. I needed this because I added a ruby-gtk3 based mp3-id-tagger some time ago.

ID3v1 tags have a 30-character limit. Thus, it is better to avoid ID3v1 and just use ID3v2.

Software such as Mp3tag can show whether the .mp3 file uses ID3v1 or ID3v2.

ID3v2 tags are also limited (nothing is infinite here), but the limit is at either 255, 32000, or 64000 some such. Even 255 already is more than enough for most text, in my opinion.

MultimediaParadise::ImdbRating

class MultimediaParadise::ImdbRating can be used to display the rating for a movie on the commandline, if it is registered as part of IMDB.

MultimediaParadise::Multimedia::VideoDownloader

class MultimediaParadise::Multimedia::VideoDownloader was added in December 2021. The idea is that whenever we want to download some remote video, this class should do that task for us. It has been designed to be re-usable from the get go.

Downloaded video files go into a directory such as this:

/home/Temp/multimedia_paradise/downloaded_videos/

This may be different on your system. Furthermore, old videos are NOT deleted, so this directory may become very big. Other classes that may merge all video files into one video file will simply pick up whatever is in that directory, so make sure to keep that directory clean before calling other classes. At a future point in time this behaviour may change, and become more user-friendly - but for now, this is documented here so that people are aware of it, until that behaviour is changed (simplified in particular).

AudioPlayer

This class is just a thin "wrapper" over mplayer or mpv really. It has been created in early June 2014.

The file can be found at multimedia_paradise/audio/audio_player/audio_player.rb.

It was originally created because I needed to play, via the commandline, audio songs in a loop - like a juke box. I wanted it to be very simple too, so no ncurses interface to it.

I also use it to perform wake-up calls in the morning, like an alarm clock.

There is an executable for this, at bin/audio_player, which acts as entry point to the code behind it, for class MultimediaParadise::AudioPlayer.

If you want to play in a loop, you can pass the argument "loop" or just "l".

Since as of the 24th February 2018, it can also act as a "timer", together with class Roebe::At, which is part of the roebe gem. For example, if you want to play random songs at the time 21:35:00, you can do:

rsong 21:35:00

Note that rsong is simply an alias that I use towards bin/audio_player. Without an alias, the above becomes:

audio_player 21:35:00

Usually I tend to use mpv, but sometimes I do use mplayer, e. g. when mpv has some problem due to recent API changes. In this case, one can specify to use mplayer on the commandline, via:

rsong 10:00:00 --use-mplayer

As already mentioned, mpv or mplayer are the two main audio players (binaries). But there are more alternatives available. For example, the program called sox has a binary called play. I have had a use case in February 2022 where neither mpv nor mplayer worked, due to a dependent library being broken (a temporary problem). As I was fixing this, I wanted to listen to music still, and added ad-hoc support for sox.

This can be triggered via:

rsong --use-sox

The binary play will be used as a result of this commandline flag.

Download videos from Google (actually Youtube)

The file google_video_downloader.rb can be used to download videos from Google - but we may have to use youtube-dl for this, which is python. This is not ideal since we use ruby :) but I am too lazy to clone the functionality of youtube-dl for now, so this just has to be glue code really. (Glue code is for lazy people and laziness can be a virtue, even if it may not be the best virtue to be had.)

For anyone who would like to give a replacement in ruby - you probably don't need to replace all of youtube-dl, only the part where we can obtain an URL. The rest can be solved by wget or curl, supposedly; or just ruby via it's open-uri functionality, for instance..

Embedding Youtube Videos

"Embedding" Youtube Videos is also possible. Note the quotes.

The code is in the file multimedia_paradise/video/youtube_embedder.rb.

Playlists

The MultimediaParadise project can generate .m3u files, as long as they are simple, e. g. one entry per line. For the purpose of the document here, we will call such .m3u files playlists.

The class responsible for the creation of .m3u files - that is playlist files - is class MultimediaParadise::CreateM3uPlaylist, residing at the location multimedia_paradise/audio/create_m3u_playlist.rb within the MultimediaParadise project.

The primary objective of this class is to generate that .m3u text file. Of course you can do so easily without the project - just do a "ls" and pipe the output it into a file, more or less - but I wanted this functionality specifically within the multimedia_paradise project, so that I can automate the creation of playlists, including batch-uploading to other websites at a later time, such as for youtube and similar remote websites. Thus I wanted to tie the functionality into the multimedia_paradise gem.

I myself use that class to generate playlists for various different song types - be these eurodance songs, trance songs, pop songs and so forth. Once such a .m3u file has been (auto)generated, it could then be used for uploading this file to an external website, as mentioned, such as to youtube or other websites that support playlists like that. Of course in order for this to work you may need to provide valid URLs to these individual remote entries somehow. The primary use case for class MultimediaParadise::CreateM3uPlaylist is for local audio files, though.

So, how to use class MultimediaParadise::CreateM3uPlaylist?

The input to class MultimediaParadise::CreateM3uPlaylist should ideally be a yaml file describing your songs (at the least the path to these songs), but you could also use the API from within Ruby, naturally and thus use a ruby array directly that is to be passed to the class; just pass this Array to .new().

Let's show a simple example for this:

MultimediaParadise::CreateM3uPlaylist.new(%( /foo/bar.mp3 /bar/foo.mp3 /tmp/dah.mp ))

You can also use this simpler toplevel method, in ruby instead:

MultimediaParadise.create_m3u_playlist()

The first argument to this method should contain the dataset that you will use for the .m3u file that is to be autogenerated. This should be a simple Array.

You can, naturally, rename the .m3u file after it has been created, since a default name will be used - the generic name used for generation of the file will be playlist.m3u.

For my own custom dataset, e. g. to generate a playlist with decent tales-from-the-crypt videos, I can just do:

playlist --tales-from-the-crypt

The MultimediaParadise project also comes with another class, called class Playlist, which has a different task. That class Playlist will handle audio-playlists, primarily. For example, it can play audio files at certain positions in the playlist.

Usage example from the commandline for this:

playlist 33,44,55

Would play the songs at position 33, then 44 and then 55. It is thus a very primitive sort of jukebox. See playlist --help for help options.

You can change positions in that playlist. To exchange position 95 with position 94, you could use input like this:

playlist "95 -> 94"

This would mean to take the song at position 95 and move it to position 94. Conversely the song at position 94 will be moved to 95; this is thus an exchange operation.

To show the entries of a playlist do:

playlist --show

(You can also omit this commandline flag since as of December

  1. This will default to show all entries in the playlist then.)

Note that by default this is adjusted to my own dataset, which is most likely totally useless to other people. You have to use your own playlist (a .yml file, called playlist.yml).

To see the available music-genres, try:

playlist --genres

In February 2022 a new class was added, called MultimediaParadise::SimulateYoutubePlaylist. The goal for this class is to "simulate" a playlist that could be used for youtube. It can also automatically create a .m3u list.

The idea here is that you can build up a playlist without depending on google necessarily. So you can add a bunch of remote URLs to youtube videos into a yaml file and have these work. They will be opened via the browser one after the other. Note that for this to work you have to install the 'open' gem, via "gem install open".

Note that as of February 2022 the class it not yet finished. It can batch-download the videos from the remote URLs given, but it is not really user-friendly yet. Stay tuned in this regard.

Normally the environment variable USE_THIS_VIDEO_PLAYER can be used to designate which multimedia player shall play these files. Since as of April 2023 it is possible to override this, via --use-mplayer, --use-vlc or --use-mpv specifically. Examples for this functionality follow next:

playlist 126,127,101 --use-mplayer
playlist 126,127,101 --use-mpv
playlist 126,127,101 --use-vlc

Watermarking videos

A watermark is a specific tag to a video. This can be a logo but it can also be used as some kind of (annoying) filter.

Whatever your use case may be, ffmpeg supports watermarking videos - and multimedia_paradise taps right into that functionality.

Adding a watermark to a video is possible and quite simple.

The class that does so, in regards to the MultimediaParadise project, is aptly called Watermark and it allows you to use FFMPEG to embed a watermark video, using the simple MultimediaParadise.watermark() method.

I rarely need to use this method so it may not be as polished as other parts of the project, though.

The default use case is to simply call that .rb file and pass a video file to it, such as shown in the following example:

vwatermark /Depot/Temp/MultimediaProject/foobar.mp4

(vwatermark is an alias on my system to simplify this. It will call the .rb file directly)

If you want to use your own image, then you have to pass an additional argument to the method, which should be the path to the image at hand.

vwatermark /Depot/Temp/MultimediaProject/foobar.mp4 /opt/my_awesome_logo.png

That's about it!

ffmpeg_merge

This file, at bin/ffmpeg_merge, was added in April 2022 to quickly merge multimedia files together, via the commandline.

Shrinking the size of .mp3 files

If you need a method to process all .mp3 files, via lame, then you can use the following method:

MultimediaParadise.shrink_quality_of_these_mp3_files(Dir['*.mp3'])

Noise in audio files (such as .mp3) and denoising these files (that is remove the noise)

Say you have some audio recording on the street, and some cars drive by or some birds chirp. This is often not wanted or even distracting.

So, how about removing that noise part? It is possible, even for simple human beings. One solution is to use sox for this task.

Note that this depends on the quality of the audio and the patterns that can be found in the noise itself, so different audio files will not work equally well. But let's assume a simple audio file and there are repetitive entities (repetitive data) inside of that stream.

sox allows the removal of these repetitive structures via the noiseprof and noisered effects of sox.

First, work on a test-audio file and let's call it foobar.mp3. Put it into an area where you can work with it.

Now that this was done, use sox to create a background noise profile from this .mp3 file:

sox foobar.mp3 -n noiseprof noise.profile

The next step is to go ahead and remove the noise from the given .mp3 file using this profile:

sox foobar.mp3 output.mp3 noisered noise.profile 0.21

These are the commandline instructions. MultimediaParadise has right now (May 2022) the first one built in as a toplevel API. Use it like this:

MultimediaParadise.create_noise_profile(of_this_mp3_file)
MultimediaParadise.create_noise_profile('foobar.mp3') # See the commandline instructions mentioned above.

Deinterlacing a video

You can deinterlace a video via this API:

MultimediaParadise.deinterlace_this_video()
MultimediaParadise.deinterlace_this_video('foobar.avi')

Converting to the .mp4 format

In my local video collection I have various .mkv files. These work fine via mpv, but if I try to play these on firefox, via the HTML5 tags, then it does not work. One solution is to convert them into .mp4 files; then they may work in the browser as well.

The multimedia_paradise gem has this enabled via the following toplevel API:

MultimediaParadise.to_mp4
MultimediaParadise.to_mp4('foobar.mkv') # Input the filename here.

This is essentially the same as issuing the following on the commandline, via ffmpeg:

ffmpeg -i foobar.mkv -vcodec copy -acodec copy foobar.mp4

So, not a huge "time saver" as such, as you can just do the above on your own. But I wanted to have this enabled within the multimedia_paradise gem. Furthermore, a file called bin/to_mp4 exists, to make available this functionality as-is.

Then the usage example on the commandline would be:

to_mp4 foobar.mkv

So this exists mostly out of convenience really.

In the long run it is planned to add many more conversion methods, such as MultimediaParadise.to_avi() and so forth. (The multimedia_paradise gem will attempt to use the most logical parameters here, if parameters are needed. Usually this just means -vcodec copy and -acodec copy, but this may not always be the case; sometimes re-encoding may occur, such as when dealing with very old video and audio codecs. But right now, it'll default to copy, for convenience and simplicity.)

Converting to a .flac file

You can use the following API to convert a file, such as foobar.mp3, into a .flac file:

MultimediaParadise.to_flac()
MultimediaParadise.to_flac('foobar.mp3')

This functionality depends on ffmpeg. The method was added mostly for convenience-reasons, as the syntax for ffmpeg itself is fairly simple: ffmpeg -i input.mp3 output.flac

Converting to an .aac file

The following API can be used to convert an audio file into a .aac file, via ffmpeg and the libvorbis audio codec:

MultimediaParadise.mp3_to_aac()
MultimediaParadise.to_aac() # This variant is shorter.

Conversions that are supported (table)

This table is mostly an overview of what is specifically supported by the multimedia_paradise gem as of May 2022.

Conversion Comment
to_aac convert into .aac format
to_ogg convert into .ogg format
to_aiff convert into .aiff format
to_wav convert into .wav format
to_webm convert into .webm format
to_mkv convert into .mkv format
to_dv convert into .dv format (Digital Video)

Converting a video file to the corresponding images

Via the toplevel method:

MultimediaParadise.video_to_images

you can convert a video to its corresponding images.

The first argument to this method should be the filename of the video-file. Specific example for this:

MultimediaParadise.video_to_images("foobar.mp4")

The second argument is the image format to use. You can just pass the Symbol :default here if you don't care about the format; this will then default to the .jpg format.

The third argument is the framerate, e. g. how many frames to convert into images per second. The default here currently is 25. Some videos require more or fewer images per second, so you may want to change this is you feel you get too many or too few images.

Usage example if you want to do only one image per second:

MultimediaParadise.video_to_images("foobar.mp4", :default, 1)

See the file multimedia_paradise/toplevel_methods/conversions.rb for more information about that functionality - it is made possible thanks to ffmpeg.

Radio stations and a graphical user interface to it (GUI)

Since as of October 2018, the MultimediaParadise project comes with a small yaml file called radio_stations.yml.

x = YAML.load_file('radio_stations.yml')

The idea here is to have a few additional audio-streams (from radio stations) that could be loaded up into, for example, rhythmbox.

I also wanted to have a default "template" for testing some ruby code there, such as autogenerating a playlist from this file, or listening to radio stations via mplayer (or mpv) and similar activities.

The file radio_stations.yml is evidently catered to my own use case. If you wish to use your own .yml file then you can do so by setting the environment variable called MULTIMEDIA_PARADISE_RADIO_STATIONS to the path of a local yaml file. For the necessary format, see the file radio_stations.yml that comes distributed with this .gem. Or, you can simply modify the .yml file as-is and add/remove any entries; keep a backup just in case perhaps.

I may listen to local internet radio stations but also to external ones, such as BBC. The following example shows how I tap into this functionality via the commandline, first by showing BBC 1:

multimedia_paradise --bbc1
multimedia_paradise --bbc2
multimedia_paradise --bbc3
multimedia_paradise --bbc4
multimedia_paradise --fm4

The above list may be extended in the future, but for now (December 2018) it shall suffice.

Do note that this functionality depends on a multimedia player, such as mpv or mplayer. See elsewhere in this document how to set to use such a multimedia player, as far as the multimedia_paradise gem is concerned.

If you would rather prefer a GUI than have to use the commandline, you could use gtk_radio, available under the bin/ directory.

This gtk-radio gtk-widget even has a stop/play/resume button, and an increase/decrease in audio volume, if ALSA is available. This GUI will list some radio stations, based on a .yml file - you could use the same format and supply your own .yml file there should you wish to use other radio stations, but support for this has not yet been added (need to re-think that part; or you just modify the .yml file as it is, then start the gtk-radio - that should work fine as well if you feel like doing this. After all it is just data stored in yaml, nothing magic about it. I may also add more radio stations if someone sends me a sensible list of these to be included by default via an email, but please include all relevant details about that radio station, most importantly the remote URL in order to tap into the remote stream; right now mpv is used for this functionality, so if that information is not available then the stream can not possibly work).

Evidently LOTS of features are missing that might make sense for any GUI about radio-streams, and some bugs may exist as well, so don't use any of these widgets in "production" or for anything serious. I will, however had, try to make the GUI components, including the www-interfaces, more useful over the coming months and years, as time (and motivation) permits.

Note that for the first 10 buttons, you can access them via the keyboard too - by pressing ALT+number, such as ALT+1 for the first button.

There is also a small bug right now in that mpv will continue to play sometimes, e. g. when the PID was not registered correctly. I have to pkill this from the commandline right now; one day in the future this bug will be squished, but for now it is better to document it as-is.

Next a few links that may be useful if you have to find out URLs to playlists:

https://marijanbloggt.at/2021/01/links-zu-streams-der-oesterreichischen-radiosender/120920

The ruby-gtk3 client currently looks like this (on IceWM):

This is far from perfect, but as a first step it should work somewhat ok-ish, as of May 2022. At a later time this may be improved visually, but for now it is how it is.

In April 2023 this was changed a bit; a mute/unmute button was added too (requires ALSA on Linux).

It now looks like this:

Not sure if this was an actual improvement, but for now it'll stay that way.

MultimediaParadise.action()

The toplevel-method MultimediaParadise.action() was added during the March 2024 rewrite of the multimedia_paradise gem.

The basic idea behind actions, implemented via the aforementioned method, is to bundle all activities that may seem useful to most users in a centralized manner.

So, for instance: say that you wish to extract the audio from a given video file, via ffmpeg. The file at hand will be called foobar.mp4.

You can generalize this via actions like in this way:

MultimediaParadise.action(:extract_audio, 'foobar.mp4')

That's it!

Of course the simpler method called MultimediaParadise.action() is also available, but the main benefit of MultimediaParadise.action() is that you do not have to require any specific file. You can ignore the file paths there, and just think in terms of actionable components. This is especially useful when we use MultimediaParadise in a GUI. It will simplify a lot of the GUI code past this point, which is why this is a win-win situation for the multimedia_paradise gem. I will eventually add java-swing components as well, thus allowing users to make use of the multimedia_paradise gem on windows as well.

Converting a .mp4 or .avi file to an animated .gif

You can use the following API to convert a video to an animated .gif:

MultimediaParadise.to_gif('foobar.mp4')

I have not yet found a way to keep a high quality here, though, so the produced .gif is not really great. Perhaps someone finds out how to keep a higher quality here.

Querying the video codec in use

If you have ffmpeg installed then you can query the video codec in use via:

MultimediaParadise.return_video_codec_of_this_file
MultimediaParadise.video_codec?
MultimediaParadise.return_video_codec_of_this_file('foobar.mp4')
MultimediaParadise.video_codec?('foobar.mp4')

This currently only works if a video has one stream. I do not know of a working syntax for querying all video streams in use, if a file has more than one stream, so keep this in mind. Most video files have only one stream though, so this method should work fine.

There is also an executable tying that functionality together, at bin/video_codec. It may then return a String on the commandline, such as "mpeg4".

GUI components of the multimedia_paradise project

Thoughts about GUIs in the multimedia_paradise gem

In December 2022 this subsection was re-arranged, to make it easer to focus on GUIs.

When we here refer to GUIs, note that web-applications, such as via sinatra, are included into this use case, as well as other languages, such as Java. Nonetheless, an important focus will also be on classical GUI elements, such as via ruby-gtk3 or ruby-libui.

The following subsections will detail more about the GUI components that are part of this project.

Graphical User Interface (GUI) and the MultimediaParadise project

A Graphical User Interface provides a human user with a simplified way to interact with a computer, via software.

Traditionally this was done primarily via a desktop-computer, the mouse (the pointer interface), the keyboard and a monitor. Nowadays the www is often used as a 'replacement' for these older graphical user interfaces, so some shift has definitely occurred, in particular in favour of 'smart' phones.

This evidently changed the way how users interact with these devices; typically no large keyboard is available on most of these devices, and an additional obvious constraint is the small screen estate.

My own primary focus, however had, is still centered around oldschool classical desktop computers, and laptops similar to such desktop computers, so I am not primarily concerned with smaller devices as such when it comes to GUIs in general. Perhaps at some later point in time this may change, but not for now. (In ruby-gtk3 this should be easily solvable via the CSS support anyway, so we could use different style sheets, depending on the interface at hand.)

How does this relate to the multimedia_paradise project?

The multimedia_paradise project tries to make use of GUIs as well.

Specifically you may be able to find ruby-gtk code that is distributed via the MultimediaParadise project that could be useful in this regard. In the past ruby-gtk2 was used for this project, but since as of the year 2021 ruby-gtk3 is the new default for all my projects when it comes to GUIs via gtk - including the MultimediaParadise project. I will not necessarily obsolete the old ruby-gtk2 deliberately so, mind you, but new code written will be in ruby-gtk3 most assuredly, and enabling ruby-gtk2 functionality is no longer a priority in this regard - at the least not for this project. Perhaps at one point in the future ruby-gtk2 will be viable again, but since GTK version 4.x is already released upstream, I think it is time to move on and away from GTK+-2.0, even though I still like this older GTK version. I am still using a GTK+-2.0 based editor, for instance.

The GTK-code made available as part of this project, in turn, depends on the project called gtk_paradise, as that project handles gtk-related parts, aside from the official upstream gtk3 gem of course. So make sure to install it as well, via gem install gtk_paradise.

Note that in general a lot of the GUI parts of MultimediaParadise are in an extremely experimental state, subject to change, and possibly filled with many unknown (and a few known) bugs - but you can have a look at some of the GUIs to see how they fare so far. An example would be the gtk-radio GUI component in particular, for ruby-gtk3. That one should work somewhat ok, although I have tested it mostly on non-systemd linux distributions only. On such a system it works quite ok-ish; the process-ID killing of mpv is super-hackish though. On windows with WSL enabled, it does not quite work yet, though; I have to find out how to be able to play sound on windows via WSL. Perhaps WSL2 simplifies this, I don't know yet.

Since as of November 2020 a basic GUI has been added that allows the user to tag .mp3 files with appropriate meta-data. This is stored in the file called tag_mp3_files.rb. (The old name was id_renamer, but this was changed in September 2021 when the application was rewritten.)

class MultimediaParadise::GUI::Gtk::TagMp3Files depends on the external library called taglib (gem install taglib-ruby), and the ruby bindings to that library, so make sure these are installed.

In the coming months this gtk-widget may be improved, but don't expect too many more upgrades to it for now - I am just glad to have finished it for now. It is more a 'fancy prototype' then a truly grandesque GUI. :)

You can also start this widget from the commandline, provided that you have the ruby-gtk bindings installed.

Example for that, on the commandline:

multimedia --gtk-tag
multimedia --tagger

In August 2021 a few things were added and it looks a bit better than it did a year ago. The current iteration looks like this on Linux (icewm) - may look different on GNOME or KDE depending on the theme in use:

In September 2021 this was rewritten slightly and it looks a bit better now, in my opinion although it stayed mostly the same nonetheless. You can compare the two images here:

A new button was added as well - the one where you can randomly open a file. This allowed me to more rapidly go through the audio files and tag them appropriately so.

Since as of February 2021, there is also a video-editor prototype available. I will add more functionality to it over the coming months, but this is a slow project, since it is a hobby-based project. The goal here would be to eventually show a per-frame widget of the video, and allow the user to make modifications to it as-is.

Since as of 2021 I am also adding libui-specific widgets. This will not look as pretty as ruby-gtk3, but the benefit is that this will work on windows, out-of-the-box by default, whereas setting up GTK on windows is much harder.

I will keep a list of which widgets are implemented (even if it is only partially implemented).

youtube_downloader.rb                # (1)
lyrics.rb                            # (2)
video_player.rb                      # (3)
simple_play_widget.rb                # (4) missing scrolled-window support in libui, though
youtube_channels.rb                  # (5) quite ok; opening in the browser does not work very well on windows right now, in August 2021, though
widget_increase_or_decrease_audio.rb # (6)

The following widgets still have to be ported:

cut_multimedia.rb
id_renamer.rb
multimedia_converter.rb
multimedia_notebook.rb
playlist.rb
play_video_from_my_collection.rb
radio.rb
sound_effect_widget.rb
video_collection.rb
video_editor.rb

If you want to start the simple_play_widget.rb on windows, you can do this:

multimedia_paradise --simple-play-widget

Usability of the GUI components that are part of the multimedia_paradise gem

I am experimenting right now, and not all GUI components may be very useful. Nonetheless, if other users are interested in GUIs, let me know what you think about the various ruby-gtk3 components that are part of the multimedia_paradise project.

Many of them are incomplete or buggy, but some parts tend to work somewhat ok-ish. I am curious which parts of the GUI tools should be improved next or extended, and how. For this, feedback would be helpful and appreciated.

Play videos from my collection via ruby-gtk3

The example file at:

gui/gtk3/play_video_from_my_collection/play_video_from_my_collection.rb

Can be used to play video files from a .yml collection. This even has a search widget which can be triggered by hitting:

Ctrl+F

As key combination.

The .yml file is adjusted to my own use case and collection so it may be utterly useless for other people - but it shows you how this works, hence why this is bundled into this project as well. If you want your own dataset, simply arrange them accordingly and change that .yml file.

The yaml file is normally at:

multimedia_paradise/yaml/video_collection/video_collection.yml

class MultimediaParadise::GUI::Gtk::ChangeMetadataWidget

You can use class MultimediaParadise::GUI::Gtk::ChangeMetadataWidget to change the meta-data of video files.

This currently (February of 2021) looks like this via ruby-gtk3:

Not very pretty, but I only wanted to show the basic functionality around this. Perhaps in the future this may be improved, but since this is mostly just a hobby and "throw-away" script please do not expect this to become really polished. I only wanted to showcase the functionality, then move on.

class MultimediaParadise::GUI::LibUI::CutMultimedia

This class can be used on windows, if you have ffmpeg installed, to cut audio files. You can download some windows binaries from the internet for this; I put ffmpeg.exe in /usr/bin/ - easier to remember for me, even on windows.

In December 2022 I tested this functionality - and it works, on windows as well. \o/

This functionality that this GUI offers is not very advanced as of yet. At a later time this may be extended. For now (December 2022) it was more important to simply add this functionality.

Creating looping video files

ffmpeg allows us to create a video playback loop of a given video. Let's assume we have the file called foobar.webm. How to loop this video file, via ffmpeg?

ffmpeg -stream_loop 10 -i input_file_goes_here.webm -c copy foobar.webm

The above commandline example would loop the given video file 10 times. That is as if you were to play it 10 times in a row without delay.

As the above functionality seemed useful, it was added to the multimedia_paradise gem in January 2023.

Usage example:

MultimediaParadise.loop_this_video('input_file.webm',  10)
MultimediaParadise.loop_this_video('input_file.webm', '10 times')
MultimediaParadise.loop_this_video('input_file.webm', '10x')

The above is all synonymous, but the first variant is probably the easiest to use.

class MultimediaParadise::Video::SplitThisVideo

class MultimediaParadise::Video::SplitThisVideo was added in February 2023 to allow us to easily split a video file.

Usage example:

require 'multimedia_paradise/video/split_this_video.rb'
MultimediaParadise::Video::SplitThisVideo.new(ARGV)
MultimediaParadise::Video::SplitThisVideo.new('foobar.avi','00:23')

You need to pass the time in 24-hour notation for now. At a later time this restriction will be relaxed.

I aliased this to split_this_video on the commandline. Then I can do this from the commandline:

splitthisvideo foobar.mpg 00:00-21:39.40

Documentation in the multimedia_paradise/www directory

In the past the multimedia_paradise gem carried documentation, in the form of .cgi pages and .sinatra files, under the directory multimedia_paradise/www.

This was mostly as a focus on audio and video related data, to help us when we want to manipulate such datasets.

In March 2023, however had, I reconsidered the old approach, and decided to put all this documentation in the roebe gem instead. That gem is where I unify most of my other projects, including documentation. I use that gem a bit like a local wiki.

class MultimediaParadise::Video::FindVideo

class MultimediaParadise::Video::FindVideo can be used to find a video registered in the local yaml file - or a yaml file supplied.

The multimedia_paradise gem comes with a yaml file that carries the dataset I use for my local video collection.

This file can be found here:

multimedia_paradise/yaml/video_collection/video_collection.yml

Obviously this is catered to my own use case and preferences so it will be totally useless to other folks. But it documents the format I use, and you can just re-use it to adjust it to your own use case.

In April 2023 class MultimediaParadise::Video::FindVideo was rewritten. It now allows users to supply their own .yml file too. That way users of this gem can work on their own dataset, as-is.

What is the use case for class MultimediaParadise::Video::FindVideo?

This class will simply find where exactly a video file is kept at. This includes support for numeric values.

For instance, I wanted to be able to do this:

play_video 235

And it should play the video that is at position 235 in that yaml file (or in the current working directory, if there is any video file that has the string "235" as part of its filename).

That way I can quickly play my local video files, without having to determine whether the file may actually be, or what the full name is. I can also supply a partial name, such as "shrek", which would expand towards the real file name of shrek 1 (the movie). This flexibility allows me to play video files from the commandline via mplayer or mpv.

So this is mostly a convenience class really.

You can supply your own yaml file via:

find_video --use-this-yaml-file=foobar.yml

Dealing with broken .mpg video files, including repairing them

I have some old video files, created by other people, most of them in .mpg format; some in container formats such as .avi.

Some of these have issues, such as:

[ffmpeg/audio] mp2: Header missing
Error decoding audio.

So, evidently, the audio has a problem here.

We should fix this - and ffmpeg may come to the rescue. \o/

Interestingly, to fix the above error, a simple -c copy can work.

Example:

ffmpeg -i input.mpg -c copy output.mpg
ffmpeg -i input.mpg -c copy output.mp4

Here both options should do fairly well; I got rid of the above error when I tried this in October 2023.

However had, the file output.mpg still raised errors such as:

[ffmpeg/demuxer] mpeg: DTS discontinuity in stream 1: packet 3 with DTS 104041, packet 4 with DTS 111240
[ffmpeg/demuxer] mpeg: DTS discontinuity in stream 1: packet 5 with DTS 111241, packet 6 with DTS 118440
[ffmpeg/demuxer] mpeg: DTS discontinuity in stream 1: packet 7 with DTS 118441, packet 8 with DTS 125640

Whereas the .mp4 file created does not yield to errors. So I think converting a .mpg file into a .mp4 is in general better.

At any rate, that got rid of the error above. But .mpg files are fairly large and I wanted to also decrease the file size. However had that is handled via another subsection in this file - please jump towards Converting a .mpg file into a .mp4 file.

Converting a .mpg file into a .mp4 file

The simplest way possible is probably this:

ffmpeg -i input.mp4 -vcodec libx265 -crf 18 -tag:v hvc1 -preset veryslow output.mp4
ffmpeg -i input.mpg -vcodec libx265 -crf 18 -tag:v hvc1 -preset veryslow output.mp4

Note that a value to crf of 0, aka -crf 0, would mean that there is lossless conversion. But the file size may be quite large, so we use a value of 18 in the above example instead.

When I tried the -crf option, though, ffmpeg reported this error:

Unrecognized option 'crf'.
Error splitting the argument list: Option not found

So right now I am a bit stuck. This may mean that the libx265 encoder was not found.

The following has worked, but it only copies the audio-codec and the video codec:

fmpeg -i "foobar.mpg" -acodec copy -vcodec copy -f mp4 barfoo.mp4

I eventually recompiled ffmpeg, and then the commandline variant was suddenly working - so, indeed, make sure your ffmpeg installation has the required codecs compiled in.

Here was the commandline variant I used:

ffmpeg -i foobar.mpg -c:v libx264 -c:a libfaac -crf 20 -preset:v veryslow output.mp4

That led to fairly large video files though.

I then tested this variant:

ffmpeg -i foobar.mpg -c:v libx265 -c:a libmp3lame -crf 28 -preset:v veryslow ANOTHER_EXAMPLE.mp4

This one seems to have better results. x265 also in general appears to be a significantly better codec than x264, so it should be used.

You may have to adjust the -crf value, but I ended up with a file size reduction of 75% of one .mpg file. Again, I am not sure how much the quality differs, but I think I may stick with the above values for the time being.

The above flags were also put into a bin/ executable, called bin/mpg_to_mp4. So the commandline invocation would be:

mpg_to_mp4 foobar.mpg

Extracting audio from any given video file

You can extract audio from any given video file, by making use of class MultimediaParadise::ExtractAudio. This presently depends on ffmpeg, so you must have ffmpeg available.

A specific usage example follows, including the require line that could be used:

require 'multimedia_paradise/audio/extract_audio/extract_audio.rb'
MultimediaParadise::ExtractAudio.new('foobar.avi')

This assumes that a video file called foobar.avi exists.

A toplevel method exists for this functionality as well:

MultimediaParadise.extract_audio(target_file_here)
MultimediaParadise.extract_audio('/tmp/foobar.avi')
MultimediaParadise.extract_audio('/home/lala.mp4')

Perhaps you may find the latter variant to be easier to read and use than the variant that uses explicit :: scoping for the instantiation of class ExtractAudio. Under the hood, both variants do the same of course.

Extracting images from a video file

The following toplevel method can be used to extract images from a video file:

MultimediaParadise.extract_images_from_this_video_file('100_0002.mov')

Simply pass in the file. This defaults to one-image-per-second, which is controlled via the second argument to this method, defaulting to 1.

I recommend to use a standalone directory for this, as quite many .png files may be created as a result.

Creating a thumbnail from a video via ffmpeg

In May 2023 I read that it is possible to create a thumbnail for a video, using ffmpeg.

The guide I was looking at was originally available here:

https://www.bannerbear.com/blog/how-to-set-a-custom-thumbnail-for-a-video-file-using-ffmpeg/

Since this was quite useful, I decided to add support for this to the multimedia_paradise gem.

The functionality and API will be demonstrated on a locally existing file. For the purpose of this document, I will use this file:

this_file = '/Depot/j/foobar.mp4'

Adjust to your use case accordingly.

Now that we have such a file, we need to know the ffmpeg-syntax to obtain a specific frame from a video file.

The following command will obtain the first frame of the video specified at the path above, in pure ffmpeg syntax (on the commandline):

ffmpeg -i /Depot/j/foobar.mp4 -frames:v 1 /Depot/j/a_new_screenshot.png

This should have created the file /Depot/j/a_new_screenshot.png.

However had, in many cases this will be a black screen image, which is not too terribly useful.

So another way may be useful here. We can tell ffmpeg to use a specific timestamp.

For instance, to capture the specific frame at 15.0 seconds, use the following command:

ffmpeg -ss 00:00:15 -i /Depot/j/foobar.mp4 -frames:v 1 ss-0015.png

(It is recommended to use the --ss option as early as possible, even before the actual filename.)

Now things get more interesting.

FFmpeg has many built-in filters. One of these filters is the Thumbnail filter. That filter will automatically select the most representative frame in a given sequence of consecutive frames from the video. This is great! \o/

How is that feature used in raw ffmpeg? Well, add the -vf "thumbnail" instructions onto the commandline.

Example:

ffmpeg -i /Depot/j/foobar.mp4 -vf "thumbnail" -frames:v 1 thumbnail.png

"thumbnail" is the name of the filter, whereas -vf is simply an alias for -filter:v.

By default, FFmpeg analyzes the frames in a batch of 100 before it then picks the most representative frame out of that batch. The process will continue until the end of the video, making sure that the best frame among all batches has been chosen for that video.

The batch size can be set on the commandline, via:

thumbnail = n # n is the number of frames.

So, for instance, if you want to pick a batch size of 300, you would use this:

ffmpeg -i /Depot/j/foobar.mp4 -vf "thumbnail=300" -frames:v 1 thumbnail-300.png

Keep in mind that a high value for n means that more memory will be used, so this may be slow on older computers. 100 seems a decent default option to use here. (Note that I modify this value every now and then to see whether I get better results; in November 2023 I am experimenting with the value 150. You may have to adjust the value for your own use cases.)

Within the multimedia_paradise gem, the following API allows you to automatically create a thumbnail from a video file.

Usage example:

require 'multimedia_paradise/toplevel_methods/toplevel_methods.rb' # ← This file includes the code shown below.
this_file = '/Depot/j/foobar.mp4'

MultimediaParadise.automatically_create_a_thumbnail_for_this_video()
MultimediaParadise.automatically_create_a_thumbnail_for_this_video(this_file)
MultimediaParadise.thumbnail(this_file) # ← This is an aliased API to the ^^^ above.

This method will return the newly generated image file. The name will be semi-generic, e. g. "thumbnail_for_", and then the raw filename of the file at hand, as a .png file. These raw filenames will be stored into an Array and this Array will then be returned, so you can write downstream code that depends on this.

The default option this method will use interally will be thumbnail=100. When I tested this in May 2023, this seemed to yield the best results.

Anyway - there are some other methods to choose "the best thumbnail", but for now the multimedia_paradise gem supports only the variant shown above. Perhaps at a later time this may be extended, but for now this is how it is.

We are not yet done, though. Now that we have the image, we must set the thumbnail for the video. This can be done by using the map option of ffmpeg. This option will choose which streams from the given input should be included in the (new) output.

The way how ffmpeg calls these options is slightly confusing. For instance, -map 1 refers to the input index #1, which is the second input. -map 0 refers to the input index #0, which is the first input - in our case the original video.

At any rate, to simplify this, prepare the .mp4 file and the image file, then do this:

ffmpeg -i /Depot/j/foobar.mp4 -i thumbnail.png -map 1 -map 0 -c copy -disposition:0 attached_pic output.mp4

This latter functionality was not yet added to the multimedia_paradise gem though - it may be added at a later time. I did, however had, test it via dolphin (from KDE) and it appears different when compared to the original .mp4 file, so the functionality provided by ffmpeg does work.

Learning to play the piano

Since early 2024 I am (again) learning to play the piano, although I use a Yamaha keyboard rather than a piano.

This subsection here will collect various snippets that may relate to playing songs, including how to practice properly. This is very random, though, as it will change as I learn new things.

Phantom of the Opera:

https://www.youtube.com/watch?v=jSWZzClCTVA

Contact information and mandatory 2FA (no longer) coming up in 2022 / 2023

If your creative mind has ideas and specific suggestions to make this gem more useful in general, feel free to drop me an email at any time, via:

shevy@inbox.lt

Before that email I used an email account at Google gmail, but in 2021 I decided to slowly abandon gmail, for various reasons. In order to limit the explanation here, allow me to just briefly state that I do not feel as if I want to promote any Google service anymore when the user becomes the end product (such as via data collection by upstream services, including other proxy-services). My feeling is that this is a hugely flawed business model to begin with, and I no longer wish to support this in any way, even if only indirectly so, such as by using services of companies that try to promote this flawed model.

In regards to responding to emails: please keep in mind that responding may take some time, depending on the amount of work I may have at that moment. So it is not that emails are ignored; it is more that I have not (yet) found the time to read and reply. This means there may be a delay of days, weeks and in some instances also months. There is, unfortunately, not much I can do when I need to prioritise my time investment, but I try to consider all feedback as an opportunity to improve my projects nonetheless.

In 2022 rubygems.org decided to make 2FA mandatory for every gem owner eventually:

see https://blog.rubygems.org/2022/06/13/making-packages-more-secure.html

However had, that has been reverted again, so I decided to shorten this paragraph. Mandatory 2FA may exclude users who do not have a smartphone device or other means to 'identify'. I do not feel it is a fair assumption by others to be made that non-identified people may not contribute code, which is why I reject it. Mandatory 2FA would mean an end to all my projects on rubygems.org, so let's hope it will never happen. (Keep in mind that I refer to mandatory 2FA; I have no qualms for people who use 2FA on their own, but this carrot-and-stick strategy by those who control the rubygems infrastructure is a very bad one to pursue.