multimedia_paradise 1.1.344 → 1.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +99 -77
- data/bin/audio_player +1 -1
- data/bin/extract_images_from_this_video_file +1 -1
- data/bin/loop_this_video +1 -1
- data/bin/merge_avi_files +1 -1
- data/bin/merge_mp3 +1 -1
- data/bin/mp3_to_opus +1 -1
- data/bin/mpg_to_mp4 +1 -1
- data/bin/multimedia_paradise +1 -1
- data/bin/to_aiff +2 -5
- data/bin/to_flac +7 -0
- data/bin/to_mp3 +8 -0
- data/bin/to_mp4 +1 -1
- data/bin/to_ogg +7 -0
- data/bin/verbose_analyse_this_mp3_file_for_id3_tags +1 -1
- data/bin/video_codec +1 -1
- data/bin/video_thumbnail +1 -1
- data/bin/video_to_images +1 -1
- data/doc/README.gen +88 -51
- data/doc/{CHANGELOG.md → changelog/changelog.md} +8 -6
- data/doc/{LINKS.md → links/links.md} +2 -2
- data/doc/{MOTIVATION_FOR_THIS_PROJECT.md → motivation_for_the_multimedia_paradise_project/motivation_for_the_multimedia_paradise_project.md} +5 -5
- data/doc/todo/todo_for_the_multimedia_paradise_project.md +79 -93
- data/lib/multimedia_paradise/actions/actions.rb +224 -0
- data/lib/multimedia_paradise/audio/audio_player/audio_player.rb +61 -64
- data/lib/multimedia_paradise/audio/audio_tag_reader/audio_tag_reader.rb +17 -8
- data/lib/multimedia_paradise/audio/base.rb +0 -5
- data/lib/multimedia_paradise/audio/compress.rb +8 -5
- data/lib/multimedia_paradise/audio/create_m3u_playlist.rb +7 -11
- data/lib/multimedia_paradise/audio/extract_audio/constants.rb +0 -37
- data/lib/multimedia_paradise/audio/extract_audio/extract_audio.rb +90 -68
- data/lib/multimedia_paradise/audio/file_duration/file_duration.rb +134 -80
- data/lib/multimedia_paradise/audio/genres/boogie.rb +1 -6
- data/lib/multimedia_paradise/audio/genres/concerts.rb +1 -6
- data/lib/multimedia_paradise/audio/genres/constants.rb +1 -1
- data/lib/multimedia_paradise/audio/genres/eurodance.rb +1 -6
- data/lib/multimedia_paradise/audio/genres/genre.rb +36 -33
- data/lib/multimedia_paradise/audio/genres/hip_hop.rb +1 -6
- data/lib/multimedia_paradise/audio/genres/italian_songs.rb +1 -6
- data/lib/multimedia_paradise/audio/genres/the_1980s.rb +1 -6
- data/lib/multimedia_paradise/audio/genres/trance.rb +4 -7
- data/lib/multimedia_paradise/audio/lyrics_fetcher.rb +27 -22
- data/lib/multimedia_paradise/audio/merge_audio_files.rb +18 -11
- data/lib/multimedia_paradise/audio/modify_year_of_audio_file.rb +23 -11
- data/lib/multimedia_paradise/audio/n_audio_songs.rb +3 -2
- data/lib/multimedia_paradise/audio/play_all_audio_files.rb +41 -16
- data/lib/multimedia_paradise/audio/playlist/playlist.rb +163 -123
- data/lib/multimedia_paradise/audio/remove_audio.rb +11 -6
- data/lib/multimedia_paradise/audio/remove_last_second.rb +2 -3
- data/lib/multimedia_paradise/audio/report_missing_id.rb +22 -12
- data/lib/multimedia_paradise/audio/streamripper/streamripper_wrapper.rb +7 -5
- data/lib/multimedia_paradise/audio/to_mp3.rb +7 -5
- data/lib/multimedia_paradise/audio/to_ogg.rb +3 -1
- data/lib/multimedia_paradise/audio/wav_to_mp3.rb +5 -5
- data/lib/multimedia_paradise/base/base.rb +854 -15
- data/lib/multimedia_paradise/base/colours.rb +28 -31
- data/lib/multimedia_paradise/base/{commandline_arguments.rb → commandline_arguments_module/commandline_arguments_module.rb} +12 -9
- data/lib/multimedia_paradise/colours/colours.rb +4 -1
- data/lib/multimedia_paradise/commandline/{menu.rb → commandline.rb} +19 -16
- data/lib/multimedia_paradise/constants/constants.rb +504 -14
- data/lib/multimedia_paradise/constants/web_constants.rb +2 -4
- data/lib/multimedia_paradise/gui/gui_base.rb +2 -2
- data/lib/multimedia_paradise/gui/libui/lyrics/lyrics.rb +1 -1
- data/lib/multimedia_paradise/gui/libui/simple_play_widget/simple_play_widget.rb +1 -1
- data/lib/multimedia_paradise/gui/libui/video_player/video_player.rb +1 -1
- data/lib/multimedia_paradise/gui/libui/youtube_channels/youtube_channels.rb +1 -1
- data/lib/multimedia_paradise/gui/shared_code/multimedia_converter/multimedia_converter_module.rb +0 -478
- data/lib/multimedia_paradise/gui/shared_code/playlist/playlist_module.rb +94 -41
- data/lib/multimedia_paradise/gui/shared_code/simple_play_widget/simple_play_widget_module.rb +0 -257
- data/lib/multimedia_paradise/gui/universal_widgets/change_metadata_widget/change_metadata_widget.rb +2 -2
- data/lib/multimedia_paradise/gui/universal_widgets/information_about_a_mp3_file/information_about_a_mp3_file.rb +1 -1
- data/lib/multimedia_paradise/gui/universal_widgets/lyrics/lyrics.rb +1 -1
- data/lib/multimedia_paradise/gui/universal_widgets/multimedia_converter/multimedia_converter.rb +589 -0
- data/lib/multimedia_paradise/gui/universal_widgets/playlist/playlist.rb +197 -0
- data/lib/multimedia_paradise/gui/universal_widgets/radio/radio.rb +1 -1
- data/lib/multimedia_paradise/gui/{gtk2 → universal_widgets}/simple_play_widget/README.md +1 -1
- data/lib/multimedia_paradise/gui/universal_widgets/simple_play_widget/simple_play_widget.rb +404 -0
- data/lib/multimedia_paradise/gui/universal_widgets/tag_mp3_files/tag_mp3_files.rb +3 -6
- data/lib/multimedia_paradise/java/Playlist.class +0 -0
- data/lib/multimedia_paradise/java/Playlist.java +198 -0
- data/lib/multimedia_paradise/multimedia/analyse_multimedia_file.rb +21 -19
- data/lib/multimedia_paradise/multimedia/avisynth/avisynth_code.avs +441 -442
- data/lib/multimedia_paradise/multimedia/base.rb +0 -18
- data/lib/multimedia_paradise/multimedia/chord.rb +1 -1
- data/lib/multimedia_paradise/multimedia/cut_multimedia/cut_multimedia.rb +7 -5
- data/lib/multimedia_paradise/multimedia/cut_multimedia/evaluate_from_this_file.rb +2 -2
- data/lib/multimedia_paradise/multimedia/interactive_shell.rb +22 -3
- data/lib/multimedia_paradise/multimedia/merge_multimedia.rb +4 -3
- data/lib/multimedia_paradise/multimedia/play_from_this_list.rb +4 -27
- data/lib/multimedia_paradise/multimedia/{read_meta_tags.rb → read_meta_tags/read_meta_tags.rb} +14 -19
- data/lib/multimedia_paradise/multimedia/start_length_duration.rb +3 -3
- data/lib/multimedia_paradise/project/project.rb +8 -4
- data/lib/multimedia_paradise/requires/require_the_multimedia_paradise_project.rb +5 -5
- data/lib/multimedia_paradise/requires/require_toplevel_methods_files.rb +1 -1
- data/lib/multimedia_paradise/sinatra/app.rb +3 -3
- data/lib/multimedia_paradise/statistics/README.md +6 -5
- data/lib/multimedia_paradise/statistics/video.rb +34 -14
- data/lib/multimedia_paradise/{misc → time}/long_format_to_milliseconds_converter.rb +4 -2
- data/lib/multimedia_paradise/{misc → time}/milliseconds_to_long_format_converter.rb +2 -2
- data/lib/multimedia_paradise/toplevel_methods/audio_related_code.rb +138 -0
- data/lib/multimedia_paradise/toplevel_methods/chop_into_segments_of_n_seconds_size.rb +2 -2
- data/lib/multimedia_paradise/{conversions → toplevel_methods}/conversions.rb +140 -48
- data/lib/multimedia_paradise/toplevel_methods/copy_and_merge_this_video_n_times.rb +5 -5
- data/lib/multimedia_paradise/toplevel_methods/create_video_from_this_audio.rb +7 -6
- data/lib/multimedia_paradise/toplevel_methods/cut_from_to.rb +2 -2
- data/lib/multimedia_paradise/toplevel_methods/denoise.rb +2 -2
- data/lib/multimedia_paradise/toplevel_methods/deshake.rb +3 -6
- data/lib/multimedia_paradise/toplevel_methods/{output_directory.rb → directory_related_code.rb} +38 -1
- data/lib/multimedia_paradise/toplevel_methods/encode_this_video.rb +8 -4
- data/lib/multimedia_paradise/toplevel_methods/esystem.rb +43 -4
- data/lib/multimedia_paradise/{ffmpeg → toplevel_methods}/ffmpeg.rb +200 -193
- data/lib/multimedia_paradise/toplevel_methods/{files_and_directories.rb → files_related_code.rb} +19 -56
- data/lib/multimedia_paradise/toplevel_methods/flip_and_rotate.rb +3 -3
- data/lib/multimedia_paradise/toplevel_methods/is_audio_file_is_video_file_is_image_file_is_multimedia_file.rb +115 -0
- data/lib/multimedia_paradise/toplevel_methods/is_on_roebe.rb +1 -1
- data/lib/multimedia_paradise/toplevel_methods/{merge_multimedia_file.rb → merge.rb} +98 -4
- data/lib/multimedia_paradise/toplevel_methods/opn.rb +5 -4
- data/lib/multimedia_paradise/toplevel_methods/player_in_use.rb +14 -7
- data/lib/multimedia_paradise/toplevel_methods/query_the_audio_codec_of_this_file.rb +4 -3
- data/lib/multimedia_paradise/toplevel_methods/radio.rb +1 -3
- data/lib/multimedia_paradise/toplevel_methods/return_all_video_files.rb +4 -4
- data/lib/multimedia_paradise/toplevel_methods/return_path_to_random_simpsons_video_file.rb +1 -1
- data/lib/multimedia_paradise/toplevel_methods/return_random_video_file_from_the_video_collection.rb +9 -7
- data/lib/multimedia_paradise/toplevel_methods/scale_video.rb +3 -4
- data/lib/multimedia_paradise/toplevel_methods/set_title_of.rb +6 -6
- data/lib/multimedia_paradise/{help/help.rb → toplevel_methods/show_help.rb} +14 -8
- data/lib/multimedia_paradise/toplevel_methods/slow_down_this_video_file.rb +2 -3
- data/lib/multimedia_paradise/toplevel_methods/start_screencast.rb +3 -2
- data/lib/multimedia_paradise/toplevel_methods/{misc.rb → toplevel_methods.rb} +485 -527
- data/lib/multimedia_paradise/toplevel_methods/total_duration.rb +4 -3
- data/lib/multimedia_paradise/toplevel_methods/use_lame_codec.rb +1 -2
- data/lib/multimedia_paradise/toplevel_methods/video_dataset.rb +1 -1
- data/lib/multimedia_paradise/version/version.rb +2 -2
- data/lib/multimedia_paradise/video/all_videos.rb +12 -19
- data/lib/multimedia_paradise/video/check_numbers.rb +76 -32
- data/lib/multimedia_paradise/video/columbo/columbo.rb +36 -14
- data/lib/multimedia_paradise/video/guess_video_name.rb +2 -10
- data/lib/multimedia_paradise/video/mike_hammer/mike_hammer.rb +2 -2
- data/lib/multimedia_paradise/video/missing_video_files/missing_video_files.rb +1 -9
- data/lib/multimedia_paradise/video/movie_searcher.rb +2 -10
- data/lib/multimedia_paradise/video/mplayer_wrapper.rb +1 -9
- data/lib/multimedia_paradise/video/random_video.rb +1 -2
- data/lib/multimedia_paradise/video/registered_video_file.rb +2 -10
- data/lib/multimedia_paradise/video/report_local_videos.rb +1 -9
- data/lib/multimedia_paradise/video/simpsons.rb +2 -10
- data/lib/multimedia_paradise/video/smart_animals/smart_animals.rb +10 -8
- data/lib/multimedia_paradise/video/speed_up_video.rb +28 -10
- data/lib/multimedia_paradise/video/store_available_video_files.rb +49 -33
- data/lib/multimedia_paradise/video/the_simpsons/README.md +0 -0
- data/lib/multimedia_paradise/video/the_simpsons/good_the_simpsons_episodes.rb +8 -8
- data/lib/multimedia_paradise/video/the_simpsons/the_simpsons.rb +14 -10
- data/lib/multimedia_paradise/video/video_information.rb +55 -49
- data/lib/multimedia_paradise/{configuration → yaml/configuration}/play_zoomed.yml +0 -0
- data/lib/multimedia_paradise/yaml/{playlist.yml → playlist/playlist.yml} +14 -15
- data/lib/multimedia_paradise/yaml/video/video.yml +1 -1
- data/lib/multimedia_paradise/yaml/video_collection/video_collection.yml +34 -32
- data/lib/multimedia_paradise/yaml/youtube/alltagsgeschichte/alltagsgeschichte.yml +61 -11
- data/lib/multimedia_paradise/yaml/youtube/songs/songs.yml +5 -3
- data/multimedia_paradise.gemspec +1 -1
- data/test/testing_audio_player.rb +3 -3
- data/test/testing_file_duration.rb +5 -5
- metadata +45 -76
- data/lib/multimedia_paradise/audio/file_duration/constants.rb +0 -53
- data/lib/multimedia_paradise/audio/waveform/class.rb +0 -341
- data/lib/multimedia_paradise/audio/waveform/constants.rb +0 -38
- data/lib/multimedia_paradise/audio/waveform/log.rb +0 -101
- data/lib/multimedia_paradise/base/constants.rb +0 -19
- data/lib/multimedia_paradise/base/encoding.rb +0 -31
- data/lib/multimedia_paradise/base/misc.rb +0 -665
- data/lib/multimedia_paradise/base/namespace.rb +0 -36
- data/lib/multimedia_paradise/base/time.rb +0 -25
- data/lib/multimedia_paradise/constants/conversions.rb +0 -62
- data/lib/multimedia_paradise/constants/directory_constants.rb +0 -139
- data/lib/multimedia_paradise/constants/encodings.rb +0 -26
- data/lib/multimedia_paradise/constants/file_constants.rb +0 -176
- data/lib/multimedia_paradise/constants/misc.rb +0 -80
- data/lib/multimedia_paradise/constants/my_video_directory.rb +0 -30
- data/lib/multimedia_paradise/constants/namespace.rb +0 -14
- data/lib/multimedia_paradise/constants/newline.rb +0 -14
- data/lib/multimedia_paradise/constants/video_filetypes.rb +0 -27
- data/lib/multimedia_paradise/conversions/README.md +0 -2
- data/lib/multimedia_paradise/ffmpeg/README.md +0 -2
- data/lib/multimedia_paradise/gui/gtk2/multimedia_converter/multimedia_converter.rb +0 -33
- data/lib/multimedia_paradise/gui/gtk2/notebook.rb +0 -144
- data/lib/multimedia_paradise/gui/gtk2/play_video_from_my_collection/play_video_from_my_collection.rb +0 -43
- data/lib/multimedia_paradise/gui/gtk2/simple_play_widget/simple_play_widget.rb +0 -40
- data/lib/multimedia_paradise/gui/gtk2/widget_increase_or_decrease_audio/widget_increase_or_decrease_audio.rb +0 -42
- data/lib/multimedia_paradise/gui/gtk2/youtube_downloader/youtube_downloader.rb +0 -32
- data/lib/multimedia_paradise/gui/gtk3/lyrics/lyrics.rb +0 -0
- data/lib/multimedia_paradise/gui/gtk3/multimedia_converter/multimedia_converter.rb +0 -34
- data/lib/multimedia_paradise/gui/gtk3/playlist/playlist.rb +0 -34
- data/lib/multimedia_paradise/gui/gtk3/simple_play_widget/simple_play_widget.rb +0 -38
- data/lib/multimedia_paradise/toplevel_methods/analyze_audio_stream.rb +0 -31
- data/lib/multimedia_paradise/toplevel_methods/codecs.rb +0 -50
- data/lib/multimedia_paradise/toplevel_methods/copy_file.rb +0 -18
- data/lib/multimedia_paradise/toplevel_methods/delay_audio.rb +0 -31
- data/lib/multimedia_paradise/toplevel_methods/ensure_that_the_output_directory_exists.rb +0 -27
- data/lib/multimedia_paradise/toplevel_methods/has_audio.rb +0 -48
- data/lib/multimedia_paradise/toplevel_methods/increase_volume_of_this_audio_file.rb +0 -61
- data/lib/multimedia_paradise/toplevel_methods/is_a_multimedia_file.rb +0 -27
- data/lib/multimedia_paradise/toplevel_methods/is_audio_file.rb +0 -27
- data/lib/multimedia_paradise/toplevel_methods/is_image_file.rb +0 -31
- data/lib/multimedia_paradise/toplevel_methods/is_video_file.rb +0 -62
- data/lib/multimedia_paradise/toplevel_methods/merge_these_videos.rb +0 -106
- data/lib/multimedia_paradise/toplevel_methods/run_sys_command.rb +0 -30
- data/lib/multimedia_paradise/toplevel_methods/to_flac.rb +0 -30
- data/lib/multimedia_paradise/toplevel_methods/to_mp4.rb +0 -24
- /data/doc/{MergingVideoLectures.md → merging_video_lectures/merging_video_lectures.md} +0 -0
- /data/doc/{Readme_for_the_cut_audio_component.md → readme_for_the_cut_audio_component/Readme_for_the_cut_audio_component.md} +0 -0
- /data/lib/multimedia_paradise/yaml/{audio_formats.yml → audio_formats/audio_formats.yml} +0 -0
- /data/lib/multimedia_paradise/yaml/{image_formats.yml → image_formats/image_formats.yml} +0 -0
- /data/lib/multimedia_paradise/yaml/{lyrics.yml → lyrics/lyrics.yml} +0 -0
- /data/lib/multimedia_paradise/yaml/{music_genres.yml → music_genres/music_genres.yml} +0 -0
- /data/lib/multimedia_paradise/yaml/{song_tags.yml → song_tags/song_tags.yml} +0 -0
- /data/lib/multimedia_paradise/yaml/{use_this_video_player.yml → use_this_video_player/use_this_video_player.yml} +0 -0
- /data/lib/multimedia_paradise/yaml/{video_encoding_settings.yml → video_encoding_settings/video_encoding_settings.yml} +0 -0
- /data/lib/multimedia_paradise/yaml/{video_filter_aliases.yml → video_filter_aliases/video_filter_aliases.yml} +0 -0
@@ -2,7 +2,7 @@
|
|
2
2
|
# Encoding: UTF-8
|
3
3
|
# frozen_string_literal: true
|
4
4
|
# =========================================================================== #
|
5
|
-
# require 'multimedia_paradise/toplevel_methods/
|
5
|
+
# require 'multimedia_paradise/toplevel_methods/toplevel_methods.rb'
|
6
6
|
# MultimediaParadise.extract_images_from_this_video_file
|
7
7
|
# MultimediaParadise.bitrate_of_this_song
|
8
8
|
# MultimediaParadise.verbose_analyse_this_mp3_file_for_id3_tags
|
@@ -11,16 +11,9 @@
|
|
11
11
|
# =========================================================================== #
|
12
12
|
module MultimediaParadise
|
13
13
|
|
14
|
-
require 'multimedia_paradise/constants/
|
14
|
+
require 'multimedia_paradise/constants/constants.rb'
|
15
15
|
require 'multimedia_paradise/toplevel_methods/esystem.rb'
|
16
|
-
require 'multimedia_paradise/
|
17
|
-
|
18
|
-
# ========================================================================= #
|
19
|
-
# === MultimediaParadise.return_all_video_files_from_the_current_directory
|
20
|
-
# ========================================================================= #
|
21
|
-
def self.return_all_video_files_from_the_current_directory
|
22
|
-
Dir['**'].select {|entry| is_a_video_file?(entry) }
|
23
|
-
end
|
16
|
+
require 'multimedia_paradise/toplevel_methods/ffmpeg.rb'
|
24
17
|
|
25
18
|
# ========================================================================= #
|
26
19
|
# === MultimediaParadise.automatically_create_a_thumbnail_for_this_video
|
@@ -50,37 +43,23 @@ module MultimediaParadise
|
|
50
43
|
end; self.instance_eval { alias thumbnail automatically_create_a_thumbnail_for_this_video } # === MultimediaParadise.thumbnail
|
51
44
|
|
52
45
|
# ========================================================================= #
|
53
|
-
# === MultimediaParadise.
|
46
|
+
# === MultimediaParadise.open_yaml_file
|
54
47
|
#
|
55
|
-
# This
|
48
|
+
# This will open my video collection.
|
49
|
+
# ========================================================================= #
|
50
|
+
def self.open_yaml_file(
|
51
|
+
i = FILE_VIDEO_COLLECTION
|
52
|
+
)
|
53
|
+
esystem "bluefish #{i}"
|
54
|
+
end
|
55
|
+
|
56
|
+
# ========================================================================= #
|
57
|
+
# === MultimediaParadise.return_all_video_files_from_the_current_directory
|
56
58
|
#
|
57
|
-
#
|
58
|
-
# the .mpg files into .mp4 files.
|
59
|
+
# This method will obtain all video-files from the current directory.
|
59
60
|
# ========================================================================= #
|
60
|
-
def self.
|
61
|
-
|
62
|
-
# Going with crf 26 - that seems to be a bit better than 25, actually.
|
63
|
-
# ======================================================================= #
|
64
|
-
crf_value_to_use = '26' # 25-28 should suffice; lower value means higher quality and larger file size.
|
65
|
-
result = []
|
66
|
-
i.flatten.each {|this_file|
|
67
|
-
this_file = File.absolute_path(this_file)
|
68
|
-
output_file = File.dirname(this_file)+'/'+
|
69
|
-
'output_'+
|
70
|
-
File.basename(this_file).
|
71
|
-
delete_suffix(
|
72
|
-
File.extname(this_file)
|
73
|
-
)+'.mp4'
|
74
|
-
_ = 'ffmpeg -i '+this_file.to_s+' -c:v libx265 -c:a libmp3lame '\
|
75
|
-
'-crf '+crf_value_to_use.to_s+' '\
|
76
|
-
'-preset:v veryslow '+
|
77
|
-
output_file
|
78
|
-
e
|
79
|
-
esystem _
|
80
|
-
e
|
81
|
-
result << File.absolute_path(output_file)
|
82
|
-
}
|
83
|
-
result # We must return the output files here.
|
61
|
+
def self.return_all_video_files_from_the_current_directory
|
62
|
+
Dir['**'].select {|entry| is_a_video_file?(entry) }
|
84
63
|
end
|
85
64
|
|
86
65
|
# ========================================================================= #
|
@@ -135,178 +114,392 @@ module MultimediaParadise
|
|
135
114
|
self.instance_eval { alias video_codec? return_video_codec_of_this_file } # === MultimediaParadise.video_codec?
|
136
115
|
|
137
116
|
# ========================================================================= #
|
138
|
-
# === MultimediaParadise.
|
117
|
+
# === MultimediaParadise.set_the_aspect_ratio_of_this_video
|
139
118
|
#
|
140
|
-
# This method will
|
141
|
-
#
|
142
|
-
def self.return_the_mpeg_layer_from_this_mp3_file(i)
|
143
|
-
cmd = "mpg123 -t #{i} 2>&1"
|
144
|
-
result = `#{cmd}`
|
145
|
-
splitted = result.split("\n")
|
146
|
-
selected = splitted.select {|line|
|
147
|
-
line.start_with? 'MPEG ' # Obtain the MPEG layer here.
|
148
|
-
}.uniq
|
149
|
-
result = selected.first # Pick the first result here.
|
150
|
-
# ======================================================================= #
|
151
|
-
# We may have to clean up that result a little bit still.
|
152
|
-
# ======================================================================= #
|
153
|
-
if result and result.include?(' ') and result.include?('III')
|
154
|
-
result = result[0 .. (result.index('III')+2)]
|
155
|
-
end
|
156
|
-
return result
|
157
|
-
end
|
158
|
-
|
159
|
-
# ========================================================================= #
|
160
|
-
# === MultimediaParadise.loop_this_video
|
119
|
+
# This method will set the aspect-ratio of a given video file, via
|
120
|
+
# ffmpeg. The commandline-flag for this is called -aspect.
|
161
121
|
#
|
162
|
-
#
|
122
|
+
# Original example:
|
163
123
|
#
|
164
|
-
#
|
124
|
+
# ffmpeg -i foo.mp4 -aspect 16:9 bar.mp4
|
165
125
|
#
|
166
|
-
#
|
126
|
+
# Example for the MultimediaParadise namespace:
|
127
|
+
#
|
128
|
+
# MultimediaParadise.set_the_aspect_ratio_of_this_video('foo.mpg')
|
167
129
|
#
|
168
130
|
# ========================================================================= #
|
169
|
-
def self.
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
131
|
+
def self.set_the_aspect_ratio_of_this_video(
|
132
|
+
this_video, use_this_aspect_ratio = '16:9'
|
133
|
+
)
|
134
|
+
extension_to_use = File.extname(this_video)
|
135
|
+
cmd_to_use = 'ffmpeg -i '+this_video+' -aspect '+
|
136
|
+
use_this_aspect_ratio+' output_'+
|
137
|
+
this_video.sub(/#{extension_to_use}$/,'')+extension_to_use
|
138
|
+
e
|
139
|
+
e cmd_to_use
|
140
|
+
e
|
141
|
+
system cmd_to_use
|
179
142
|
end
|
180
143
|
|
181
144
|
# ========================================================================= #
|
182
|
-
# === MultimediaParadise.
|
145
|
+
# === MultimediaParadise.load_yaml
|
183
146
|
# ========================================================================= #
|
184
|
-
def self.
|
185
|
-
|
186
|
-
end
|
147
|
+
def self.load_yaml(i)
|
148
|
+
YAML.load_file(i)
|
149
|
+
end
|
187
150
|
|
188
151
|
# ========================================================================= #
|
189
|
-
# === MultimediaParadise.
|
190
|
-
#
|
191
|
-
# This method can be used to copy the content of the bin/ directory
|
192
|
-
# onto the current working directory.
|
193
|
-
#
|
194
|
-
# Usage example from within ruby code:
|
152
|
+
# === MultimediaParadise.flip_video_to_the_left
|
195
153
|
#
|
196
|
-
#
|
154
|
+
# This toplevel-method can be used to flip a video to the left,
|
155
|
+
# that is, to rotate it by -90 degrees.
|
197
156
|
#
|
157
|
+
# It will tap into ffmpeg for this task.
|
198
158
|
# ========================================================================= #
|
199
|
-
def self.
|
200
|
-
|
201
|
-
"yaml/internal/installed_binaries.yml"
|
202
|
-
mkdir('bin/')
|
203
|
-
cd('bin/')
|
204
|
-
if File.exist? file_installed_binaries
|
205
|
-
e 'Making use of the file '+sfile(file_installed_binaries)+'.'
|
206
|
-
install_these_binaries = YAML.load_file(file_installed_binaries)
|
207
|
-
installation_directory = `gem env`.split("\n").select {|line| # Check for INSTALLATION DIRECTORY: /root/.gem
|
208
|
-
line.include? 'INSTALLATION DIRECTORY:'
|
209
|
-
}.first.
|
210
|
-
scan(/INSTALLATION DIRECTORY: (.+)$/).flatten.first
|
211
|
-
install_these_binaries.each {|entry|
|
212
|
-
target = installation_directory+'/bin/'+entry
|
213
|
-
if File.exist? target
|
214
|
-
e "Copying the file #{target} into the current working "\
|
215
|
-
"directory next."
|
216
|
-
copy_file(target, Dir.pwd)
|
217
|
-
else
|
218
|
-
# ================================================================= #
|
219
|
-
# Since as of January 2023 first try the bin_dir, before giving up.
|
220
|
-
# ================================================================= #
|
221
|
-
target = MultimediaParadise.bin_dir?+File.basename(entry)
|
222
|
-
if File.exist? target
|
223
|
-
e "Copying the file #{target} into the current working "\
|
224
|
-
"directory next."
|
225
|
-
copy_file(target, Dir.pwd)
|
226
|
-
else
|
227
|
-
no_file_exists_at(target)
|
228
|
-
end
|
229
|
-
end
|
230
|
-
}
|
231
|
-
end
|
159
|
+
def self.flip_video_to_the_left(i)
|
160
|
+
ffmpeg_flip_video_to_the_left(i)
|
232
161
|
end
|
233
162
|
|
234
163
|
# ========================================================================= #
|
235
|
-
# === MultimediaParadise.
|
236
|
-
#
|
237
|
-
# This method can be used to quickly turn an .avi file or a .mp4
|
238
|
-
# file into an animated .gif.
|
239
|
-
#
|
240
|
-
# The quality is pretty low, so this is not ideal, but if you
|
241
|
-
# have a use case for animated .gif files then this is one
|
242
|
-
# way to do so.
|
243
|
-
#
|
244
|
-
# Usage example:
|
245
|
-
#
|
246
|
-
# MultimediaParadise.to_gif('foobar.mp4')
|
164
|
+
# === MultimediaParadise.flip_video_to_the_right
|
247
165
|
#
|
166
|
+
# This toplevel-method can be used to flip a video to the right,
|
167
|
+
# that is, to rotate it by +90 degrees.
|
248
168
|
# ========================================================================= #
|
249
|
-
def self.
|
250
|
-
|
251
|
-
_ = File.basename(this_video_file).
|
252
|
-
delete_suffix(
|
253
|
-
File.extname(this_video_file)
|
254
|
-
)
|
255
|
-
name_of_the_output_gif_file = "output_#{_}.gif"
|
256
|
-
cmd = "ffmpeg -i #{this_video_file} -pix_fmt rgb8 #{name_of_the_output_gif_file}" # Or use 0rgb.
|
257
|
-
esystem(cmd)
|
258
|
-
return name_of_the_output_gif_file
|
259
|
-
}
|
169
|
+
def self.flip_video_to_the_right(i)
|
170
|
+
ffmpeg_flip_video_to_the_right(i)
|
260
171
|
end
|
261
|
-
|
172
|
+
|
262
173
|
# ========================================================================= #
|
263
|
-
# === MultimediaParadise.
|
264
|
-
#
|
265
|
-
# Note that this method depends on the external program called "sox".
|
266
|
-
#
|
267
|
-
# Usage example:
|
268
|
-
#
|
269
|
-
# MultimediaParadise.create_noise_profile('foobar.mp3')
|
174
|
+
# === MultimediaParadise.compress_this_ogg_file
|
270
175
|
#
|
176
|
+
# This method will use a sampling rate of 22050 Hz. This should be
|
177
|
+
# perfectly adequate for speech-related audio, but I also found it
|
178
|
+
# to work well when compressing a tetris.ogg file (for the game
|
179
|
+
# tetris).
|
271
180
|
# ========================================================================= #
|
272
|
-
def self.
|
273
|
-
|
181
|
+
def self.compress_this_ogg_file(i = 'foobar.ogg')
|
182
|
+
_ = 'ffmpeg -i '+entry+' '\
|
183
|
+
'-c:a libvorbis -ab 32k '\
|
184
|
+
'-ar 22050'\
|
185
|
+
' OUTPUT_'+i
|
186
|
+
e
|
187
|
+
esystem _
|
188
|
+
e
|
189
|
+
end
|
190
|
+
|
191
|
+
# ========================================================================= #
|
192
|
+
# === MultimediaParadise.try_to_rename_kde_konsole_tab
|
193
|
+
# ========================================================================= #
|
194
|
+
def self.try_to_rename_kde_konsole_tab(
|
195
|
+
new_title = '_',
|
196
|
+
try_to_rename_the_kde_konsole_tab = TRY_TO_RENAME_THE_KDE_KONSOLE_TAB
|
274
197
|
)
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
if File.exist?(this_profile_file_is_to_be_created) # Always remove old profiles.
|
281
|
-
File.delete(this_profile_file_is_to_be_created)
|
198
|
+
if try_to_rename_the_kde_konsole_tab
|
199
|
+
begin
|
200
|
+
require 'roebe/requires/require_kde_konsole.rb'
|
201
|
+
rescue LoadError
|
202
|
+
e 'roebe/requires/require_kde_konsole.rb is not available'
|
282
203
|
end
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
204
|
+
if Object.const_defined?(:Roebe) and
|
205
|
+
Roebe.respond_to?(:rename_konsole)
|
206
|
+
Roebe.rename_konsole(new_title)
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end; self.instance_eval { alias rename_kde_konsole try_to_rename_kde_konsole_tab } # === MultimediaParadise.rename_kde_konsole
|
210
|
+
self.instance_eval { alias do_rename_konsole try_to_rename_kde_konsole_tab } # === MultimediaParadise.do_rename_konsole
|
211
|
+
self.instance_eval { alias rename_kde_konsole_tab try_to_rename_kde_konsole_tab } # === MultimediaParadise.rename_kde_konsole_tab
|
290
212
|
|
291
213
|
# ========================================================================= #
|
292
|
-
# === MultimediaParadise.
|
214
|
+
# === MultimediaParadise.crop_this_video
|
293
215
|
#
|
294
|
-
# This method can be used to
|
216
|
+
# This method can be used to crop a particular video file, via
|
217
|
+
# ffmpeg.
|
295
218
|
#
|
296
|
-
#
|
219
|
+
# The raw ffmpeg-command would go like something like this:
|
297
220
|
#
|
298
|
-
#
|
221
|
+
# ffmpeg -i input.mp4 -filter:v "crop=out_w:out_h:x:y" output.mp4
|
222
|
+
#
|
223
|
+
# These variables are:
|
224
|
+
#
|
225
|
+
# → out_w is the width of the output rectangle
|
226
|
+
# → out_h is the height of the output rectangle
|
227
|
+
# → x and y specify the top left corner of the output rectangle
|
228
|
+
# → output.mp4 is the output file
|
299
229
|
#
|
300
230
|
# ========================================================================= #
|
301
|
-
def self.
|
302
|
-
|
303
|
-
|
231
|
+
def self.crop_this_video(
|
232
|
+
i = 'input.mp4',
|
233
|
+
output_file = 'output.mp4'
|
234
|
+
)
|
235
|
+
[i].flatten.compact.each {|this_video_file|
|
236
|
+
esystem 'ffmpeg -i '+
|
237
|
+
this_video_file.to_s+
|
238
|
+
' -filter:v "crop=w:h:x:y" '+
|
239
|
+
output_file.to_s
|
304
240
|
}
|
305
241
|
end
|
306
242
|
|
307
243
|
# ========================================================================= #
|
308
|
-
# ===
|
309
|
-
#
|
244
|
+
# === glob
|
245
|
+
# ========================================================================= #
|
246
|
+
def glob(i)
|
247
|
+
Dir[i]
|
248
|
+
end
|
249
|
+
|
250
|
+
# ========================================================================= #
|
251
|
+
# === MultimediaParadise::PLAY_ZOOMED
|
252
|
+
#
|
253
|
+
# If this constant is set to true, then we will play in a zoomed way.
|
254
|
+
# ========================================================================= #
|
255
|
+
PLAY_ZOOMED = YAML.load_file(
|
256
|
+
"#{project_yaml_directory?}configuration/play_zoomed.yml"
|
257
|
+
)
|
258
|
+
|
259
|
+
# ========================================================================= #
|
260
|
+
# === MultimediaParadise.verbose_analyse_this_mp3_file_for_id3_tags
|
261
|
+
# ========================================================================= #
|
262
|
+
def self.verbose_analyse_this_mp3_file_for_id3_tags(this_mp3_file)
|
263
|
+
require 'id3lib'
|
264
|
+
if this_mp3_file.is_a? Array
|
265
|
+
this_mp3_file.each {|entry|
|
266
|
+
verbose_analyse_this_mp3_file_for_id3_tags(entry)
|
267
|
+
}
|
268
|
+
else
|
269
|
+
dataset = ID3Lib::Tag.new(this_mp3_file)
|
270
|
+
e "#{::Colours.rev}"\
|
271
|
+
"The .mp3 file is called: #{sfancy(this_mp3_file)}"
|
272
|
+
if dataset.empty?
|
273
|
+
e 'Has no id3-tags!'
|
274
|
+
else
|
275
|
+
# e 'Has some id3-tags.' # <- Dont report this in this case, though.
|
276
|
+
# ===================================================================== #
|
277
|
+
# Iterate through these entries next.
|
278
|
+
# ===================================================================== #
|
279
|
+
dataset.each_entry {|inner_hash|
|
280
|
+
value = inner_hash[:text].to_s
|
281
|
+
case inner_hash[:id]
|
282
|
+
# =================================================================== #
|
283
|
+
# === :TIT2
|
284
|
+
# =================================================================== #
|
285
|
+
when :TIT2
|
286
|
+
e 'The title is: '+
|
287
|
+
Colours.steelblue(value) unless value.empty?
|
288
|
+
# =================================================================== #
|
289
|
+
# === :TCON
|
290
|
+
#
|
291
|
+
# The genre.
|
292
|
+
# =================================================================== #
|
293
|
+
when :TCON
|
294
|
+
e 'The genre is: '+
|
295
|
+
Colours.steelblue(value) unless value.empty?
|
296
|
+
# =================================================================== #
|
297
|
+
# === :TYER
|
298
|
+
#
|
299
|
+
# The year.
|
300
|
+
# =================================================================== #
|
301
|
+
when :TYER
|
302
|
+
e 'The year is: '+
|
303
|
+
Colours.steelblue(value) unless value.empty?
|
304
|
+
# =================================================================== #
|
305
|
+
# === :TPE1
|
306
|
+
#
|
307
|
+
# The artist.
|
308
|
+
# =================================================================== #
|
309
|
+
when :TPE1
|
310
|
+
e 'The artist is: '+
|
311
|
+
Colours.steelblue(value) unless value.empty?
|
312
|
+
end
|
313
|
+
}
|
314
|
+
# pp dataset # <- for debugging.
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
# ========================================================================= #
|
320
|
+
# === MultimediaParadise.analyze_this_directory_for_id3_tags
|
321
|
+
# ========================================================================= #
|
322
|
+
def self.analyze_this_directory_for_id3_tags(i = Dir.pwd)
|
323
|
+
require 'id3lib'
|
324
|
+
all_files = Dir["#{i}/*.mp3"]
|
325
|
+
all_files.each {|this_mp3_file|
|
326
|
+
verbose_analyse_this_mp3_file_for_id3_tags(this_mp3_file)
|
327
|
+
}
|
328
|
+
end
|
329
|
+
|
330
|
+
# ========================================================================= #
|
331
|
+
# === MultimediaParadise.high_quality_transcoding_of_this_video_file
|
332
|
+
#
|
333
|
+
# This method can be used for high-quality transcoding of a given
|
334
|
+
# input video file.
|
335
|
+
#
|
336
|
+
# - C:V is the video codec of choice
|
337
|
+
# - preset is the compression preset (in this case slow for higher
|
338
|
+
# quality compression)
|
339
|
+
# - CRF is the Constant Rate Factor, which preserves an overall
|
340
|
+
# level of quality throughout the file by adjusting each frame's
|
341
|
+
# bitrate based on the given quality level. The higher the CRF,
|
342
|
+
# the lower the overall quality level.
|
343
|
+
# - The video filter flag (-vf) is used to call FFMPEG's pre-bundled
|
344
|
+
# video filters.
|
345
|
+
# - yadif (Yet Another Deinterlacing Filter) deinterlaces an interlaced
|
346
|
+
# input, as progressive video is not only easier to compress and most
|
347
|
+
# current computer monitors and televisions are progressive scan.
|
348
|
+
# - When encoding with H.264/MPEG-4 AVC, the audio format used is AAC
|
349
|
+
# (Advanced Audio Coding); in order to enable FFMPEG's experimental,
|
350
|
+
# native AAC encoder.
|
351
|
+
# - -strict -2 needs to be added to the command.
|
352
|
+
# - An external library such as libfaac can also be used, and -strict
|
353
|
+
# -2 can be omitted.
|
354
|
+
#
|
355
|
+
# ========================================================================= #
|
356
|
+
def self.high_quality_transcoding_of_this_video_file(this_video_file)
|
357
|
+
output_file = 'OUTPUT_'+this_video_file.
|
358
|
+
sub(/#{File.extname(this_video_file)}$/,'')+'.mp4'
|
359
|
+
_ = 'ffmpeg -i '+this_video_file+' -c:v libx264 -preset slow '\
|
360
|
+
'-crf 18 -vf yadif -strict -2 '+
|
361
|
+
output_file
|
362
|
+
e
|
363
|
+
esystem _
|
364
|
+
e
|
365
|
+
end; self.instance_eval { alias high_quality_transcoding high_quality_transcoding_of_this_video_file } # === MultimediaParadise.high_quality_transcoding
|
366
|
+
|
367
|
+
# ========================================================================= #
|
368
|
+
# === MultimediaParadise.identify_video
|
369
|
+
#
|
370
|
+
# Use this to identify a given video or audio file.
|
371
|
+
#
|
372
|
+
# Another way would be this:
|
373
|
+
#
|
374
|
+
# mplayer -vo null -ao null -frames 0 -identify POP_America_TheLastUnicorn.mp3
|
375
|
+
#
|
376
|
+
# You will have to parse this lateron.
|
377
|
+
# ========================================================================= #
|
378
|
+
def self.identify_video(this_file)
|
379
|
+
cmd = "ffmpeg -i #{this_file}"
|
380
|
+
e
|
381
|
+
e cmd
|
382
|
+
e
|
383
|
+
result = `{cmd}`
|
384
|
+
return result
|
385
|
+
end
|
386
|
+
|
387
|
+
# ========================================================================= #
|
388
|
+
# === MultimediaParadise.show_available_audio_formats
|
389
|
+
#
|
390
|
+
# Use this method if you want to show the available (registered)
|
391
|
+
# audio formats.
|
392
|
+
# ========================================================================= #
|
393
|
+
def self.show_available_audio_formats
|
394
|
+
e; AUDIO_FORMATS.each {|entry|
|
395
|
+
e " - #{entry}" # It is ok to prepend the '-' since this is for display purposes.
|
396
|
+
}; e
|
397
|
+
end
|
398
|
+
|
399
|
+
# ========================================================================= #
|
400
|
+
# === MultimediaParadise.show_artist
|
401
|
+
#
|
402
|
+
# Use this for .mp3 files, via ffmpeg. It will show the artist.
|
403
|
+
#
|
404
|
+
# Input should be a .mp3 file.
|
405
|
+
#
|
406
|
+
# Usage example from within ruby code:
|
407
|
+
#
|
408
|
+
# MultimediaParadise.show_artist('/Depot/Audio/YoutubeMix_VivaldisFourSeasons.mp3')
|
409
|
+
# MultimediaParadise.show_artist('/Depot/Audio/Vivaldi_Concerto8.mp3')
|
410
|
+
#
|
411
|
+
# ========================================================================= #
|
412
|
+
def self.show_artist(
|
413
|
+
i, report_classname = true
|
414
|
+
)
|
415
|
+
result = MultimediaParadise.return_artist(i)
|
416
|
+
if result.empty?
|
417
|
+
opnn if report_classname
|
418
|
+
e 'This file does not have any artist-tag.'
|
419
|
+
else
|
420
|
+
opnn if report_classname
|
421
|
+
e "The artist is: #{simp(result)}"
|
422
|
+
end
|
423
|
+
end
|
424
|
+
|
425
|
+
# ========================================================================= #
|
426
|
+
# === MultimediaParadise.return_artist
|
427
|
+
# ========================================================================= #
|
428
|
+
def self.return_artist(
|
429
|
+
i,
|
430
|
+
report_classname = true
|
431
|
+
)
|
432
|
+
i = i.to_s
|
433
|
+
cmd =
|
434
|
+
'ffprobe -loglevel error -show_entries format_tags=artist '\
|
435
|
+
'-of default=noprint_wrappers=1:nokey=1 '+i
|
436
|
+
result = `#{cmd}`.chomp
|
437
|
+
return result
|
438
|
+
end
|
439
|
+
|
440
|
+
# ========================================================================= #
|
441
|
+
# === MultimediaParadise.decrease_volume
|
442
|
+
#
|
443
|
+
# This should decrease audio volume, by using sox.
|
444
|
+
#
|
445
|
+
# We do this by using the command --volume FACTOR.
|
446
|
+
# ========================================================================= #
|
447
|
+
def self.decrease_volume(
|
448
|
+
of_this_file,
|
449
|
+
by_how_much = '0.5'
|
450
|
+
)
|
451
|
+
run_sys_command 'sox --volume '+
|
452
|
+
by_how_much+' '+of_this_file+' AUDIO_REDUCED_'+of_this_file
|
453
|
+
end
|
454
|
+
|
455
|
+
# ========================================================================= #
|
456
|
+
# === MultimediaParadise.create_noise_profile
|
457
|
+
#
|
458
|
+
# Note that this method depends on the external program called "sox".
|
459
|
+
#
|
460
|
+
# Usage example:
|
461
|
+
#
|
462
|
+
# MultimediaParadise.create_noise_profile('foobar.mp3')
|
463
|
+
#
|
464
|
+
# ========================================================================= #
|
465
|
+
def self.create_noise_profile(
|
466
|
+
of_this_mp3_file
|
467
|
+
)
|
468
|
+
array_results = []
|
469
|
+
[of_this_mp3_file].flatten.compact.each {|work_on_this_mp3_file|
|
470
|
+
work_on_this_mp3_file = File.absolute_path(work_on_this_mp3_file)
|
471
|
+
filename_without_extension = work_on_this_mp3_file.delete_suffix('.mp3')
|
472
|
+
this_profile_file_is_to_be_created = "noise_profile_based_on_#{File.basename(filename_without_extension)}"
|
473
|
+
if File.exist?(this_profile_file_is_to_be_created) # Always remove old profiles.
|
474
|
+
File.delete(this_profile_file_is_to_be_created)
|
475
|
+
end
|
476
|
+
cmd_to_run = "sox #{work_on_this_mp3_file} -n noiseprof #{this_profile_file_is_to_be_created}.profile"
|
477
|
+
e cmd_to_run
|
478
|
+
`#{cmd_to_run}`
|
479
|
+
array_results << this_profile_file_is_to_be_created
|
480
|
+
}
|
481
|
+
return array_results
|
482
|
+
end
|
483
|
+
|
484
|
+
# ========================================================================= #
|
485
|
+
# === MultimediaParadise.shrink_quality_of_these_mp3_files
|
486
|
+
#
|
487
|
+
# This method can be used to batch-shrink several .mp3 files in one go.
|
488
|
+
#
|
489
|
+
# Usage example:
|
490
|
+
#
|
491
|
+
# MultimediaParadise.shrink_quality_of_these_mp3_files(Dir['*.mp3'])
|
492
|
+
#
|
493
|
+
# ========================================================================= #
|
494
|
+
def self.shrink_quality_of_these_mp3_files(*array)
|
495
|
+
array.flatten.each {|this_mp3_file|
|
496
|
+
esystem "lame --mp3input -b 64 #{this_mp3_file}"
|
497
|
+
}
|
498
|
+
end
|
499
|
+
|
500
|
+
# ========================================================================= #
|
501
|
+
# === MultimediaParadise.report_how_many_real_videos_are_stored
|
502
|
+
#
|
310
503
|
# This method will report how many "real" videos are stored in the
|
311
504
|
# file video_collection.yml, which is distributed as part of
|
312
505
|
# this gem. You can, however had, also specify your own .yml
|
@@ -563,402 +756,167 @@ module MultimediaParadise
|
|
563
756
|
end
|
564
757
|
|
565
758
|
# ========================================================================= #
|
566
|
-
# === MultimediaParadise.
|
759
|
+
# === MultimediaParadise.mpg_to_mp4
|
760
|
+
#
|
761
|
+
# This is an opinionated method.
|
567
762
|
#
|
568
|
-
#
|
763
|
+
# You have to pass the filename to this method, in order to convert
|
764
|
+
# the .mpg files into .mp4 files.
|
569
765
|
# ========================================================================= #
|
570
|
-
def self.
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
766
|
+
def self.mpg_to_mp4(*i)
|
767
|
+
# ======================================================================= #
|
768
|
+
# Going with crf 26 - that seems to be a bit better than 25, actually.
|
769
|
+
# ======================================================================= #
|
770
|
+
crf_value_to_use = '26' # 25-28 should suffice; lower value means higher quality and larger file size.
|
771
|
+
result = []
|
772
|
+
i.flatten.each {|this_file|
|
773
|
+
this_file = File.absolute_path(this_file)
|
774
|
+
output_file = File.dirname(this_file)+'/'+
|
775
|
+
'output_'+
|
776
|
+
File.basename(this_file).
|
777
|
+
delete_suffix(
|
778
|
+
File.extname(this_file)
|
779
|
+
)+'.mp4'
|
780
|
+
_ = 'ffmpeg -i '+this_file.to_s+' -c:v libx265 -c:a libmp3lame '\
|
781
|
+
'-crf '+crf_value_to_use.to_s+' '\
|
782
|
+
'-preset:v veryslow '+
|
783
|
+
output_file
|
784
|
+
e
|
785
|
+
esystem _
|
786
|
+
e
|
787
|
+
result << File.absolute_path(output_file)
|
579
788
|
}
|
789
|
+
result # We must return the output files here.
|
580
790
|
end
|
581
791
|
|
582
792
|
# ========================================================================= #
|
583
|
-
# === MultimediaParadise.
|
584
|
-
#
|
585
|
-
# This method will set the aspect-ratio of a given video file, via
|
586
|
-
# ffmpeg. The commandline-flag for this is called -aspect.
|
587
|
-
#
|
588
|
-
# Original example:
|
589
|
-
#
|
590
|
-
# ffmpeg -i foo.mp4 -aspect 16:9 bar.mp4
|
591
|
-
#
|
592
|
-
# Example for the MultimediaParadise namespace:
|
593
|
-
#
|
594
|
-
# MultimediaParadise.set_the_aspect_ratio_of_this_video('foo.mpg')
|
595
|
-
#
|
596
|
-
# ========================================================================= #
|
597
|
-
def self.set_the_aspect_ratio_of_this_video(
|
598
|
-
this_video, use_this_aspect_ratio = '16:9'
|
599
|
-
)
|
600
|
-
extension_to_use = File.extname(this_video)
|
601
|
-
cmd_to_use = 'ffmpeg -i '+this_video+' -aspect '+
|
602
|
-
use_this_aspect_ratio+' output_'+
|
603
|
-
this_video.sub(/#{extension_to_use}$/,'')+extension_to_use
|
604
|
-
e
|
605
|
-
e cmd_to_use
|
606
|
-
e
|
607
|
-
system cmd_to_use
|
608
|
-
end
|
609
|
-
|
610
|
-
# ========================================================================= #
|
611
|
-
# === MultimediaParadise.extract_one_image_per_second
|
612
|
-
#
|
613
|
-
# This method will extract one-image-per-second from a given
|
614
|
-
# input video file.
|
615
|
-
#
|
616
|
-
# The first argument to this method should be the video file you
|
617
|
-
# are working with, such as 'foobar.mp4'.
|
618
|
-
# ========================================================================= #
|
619
|
-
def self.extract_one_image_per_second(
|
620
|
-
from_this_video_file = 'my_video.mpeg',
|
621
|
-
frame_size_to_use = '75x75'
|
622
|
-
)
|
623
|
-
extension_to_use = File.extname(from_this_video_file)
|
624
|
-
_ = 'ffmpeg -i '+from_this_video_file+
|
625
|
-
' -r 1 '+ # ← Specify the video-frame here, aka "1 image per second".
|
626
|
-
'-s '+frame_size_to_use+
|
627
|
-
' OUTPUT_'+from_this_video_file.sub(/#{extension_to_use}$/,'')+
|
628
|
-
extension_to_use
|
629
|
-
e
|
630
|
-
esystem _
|
631
|
-
e
|
632
|
-
end
|
633
|
-
|
634
|
-
# ========================================================================= #
|
635
|
-
# === MultimediaParadise.convert_these_images_into_a_video
|
636
|
-
#
|
637
|
-
# This method can be used to "assemble" images into a video.
|
638
|
-
# ========================================================================= #
|
639
|
-
def self.convert_these_images_into_a_video(*images)
|
640
|
-
_ = 'ffmpeg -f image2 -i '+images.join(' ').strip+' video.mpg'
|
641
|
-
esystem _
|
642
|
-
end
|
643
|
-
|
644
|
-
# ========================================================================= #
|
645
|
-
# === MultimediaParadise.high_quality_transcoding_of_this_video_file
|
646
|
-
#
|
647
|
-
# This method can be used for high-quality transcoding of a given
|
648
|
-
# input video file.
|
649
|
-
#
|
650
|
-
# - C:V is the video codec of choice
|
651
|
-
# - preset is the compression preset (in this case slow for higher
|
652
|
-
# quality compression)
|
653
|
-
# - CRF is the Constant Rate Factor, which preserves an overall
|
654
|
-
# level of quality throughout the file by adjusting each frame's
|
655
|
-
# bitrate based on the given quality level. The higher the CRF,
|
656
|
-
# the lower the overall quality level.
|
657
|
-
# - The video filter flag (-vf) is used to call FFMPEG's pre-bundled
|
658
|
-
# video filters.
|
659
|
-
# - yadif (Yet Another Deinterlacing Filter) deinterlaces an interlaced
|
660
|
-
# input, as progressive video is not only easier to compress and most
|
661
|
-
# current computer monitors and televisions are progressive scan.
|
662
|
-
# - When encoding with H.264/MPEG-4 AVC, the audio format used is AAC
|
663
|
-
# (Advanced Audio Coding); in order to enable FFMPEG's experimental,
|
664
|
-
# native AAC encoder.
|
665
|
-
# - -strict -2 needs to be added to the command.
|
666
|
-
# - An external library such as libfaac can also be used, and -strict
|
667
|
-
# -2 can be omitted.
|
668
|
-
#
|
669
|
-
# ========================================================================= #
|
670
|
-
def self.high_quality_transcoding_of_this_video_file(this_video_file)
|
671
|
-
output_file = 'OUTPUT_'+this_video_file.
|
672
|
-
sub(/#{File.extname(this_video_file)}$/,'')+'.mp4'
|
673
|
-
_ = 'ffmpeg -i '+this_video_file+' -c:v libx264 -preset slow '\
|
674
|
-
'-crf 18 -vf yadif -strict -2 '+
|
675
|
-
output_file
|
676
|
-
e
|
677
|
-
esystem _
|
678
|
-
e
|
679
|
-
end; self.instance_eval { alias high_quality_transcoding high_quality_transcoding_of_this_video_file } # === MultimediaParadise.high_quality_transcoding
|
680
|
-
|
681
|
-
# ========================================================================= #
|
682
|
-
# === MultimediaParadise.identify_video
|
683
|
-
#
|
684
|
-
# Use this to identify a given video or audio file.
|
685
|
-
#
|
686
|
-
# Another way would be this:
|
687
|
-
#
|
688
|
-
# mplayer -vo null -ao null -frames 0 -identify POP_America_TheLastUnicorn.mp3
|
793
|
+
# === MultimediaParadise.return_the_mpeg_layer_from_this_mp3_file
|
689
794
|
#
|
690
|
-
#
|
795
|
+
# This method will make use of the binary called "mpg123".
|
691
796
|
# ========================================================================= #
|
692
|
-
def self.
|
693
|
-
cmd = "
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
797
|
+
def self.return_the_mpeg_layer_from_this_mp3_file(i)
|
798
|
+
cmd = "mpg123 -t #{i} 2>&1"
|
799
|
+
result = `#{cmd}`
|
800
|
+
splitted = result.split("\n")
|
801
|
+
selected = splitted.select {|line|
|
802
|
+
line.start_with? 'MPEG ' # Obtain the MPEG layer here.
|
803
|
+
}.uniq
|
804
|
+
result = selected.first # Pick the first result here.
|
805
|
+
# ======================================================================= #
|
806
|
+
# We may have to clean up that result a little bit still.
|
807
|
+
# ======================================================================= #
|
808
|
+
if result and result.include?(' ') and result.include?('III')
|
809
|
+
result = result[0 .. (result.index('III')+2)]
|
810
|
+
end
|
698
811
|
return result
|
699
812
|
end
|
700
813
|
|
701
814
|
# ========================================================================= #
|
702
|
-
# === MultimediaParadise.
|
703
|
-
#
|
704
|
-
# Use this method if you want to show the available (registered)
|
705
|
-
# audio formats.
|
706
|
-
# ========================================================================= #
|
707
|
-
def self.show_available_audio_formats
|
708
|
-
e; AUDIO_FORMATS.each {|entry|
|
709
|
-
e " - #{entry}" # It is ok to prepend the '-' since this is for display purposes.
|
710
|
-
}; e
|
711
|
-
end
|
712
|
-
|
713
|
-
# ========================================================================= #
|
714
|
-
# === MultimediaParadise.show_artist
|
715
|
-
#
|
716
|
-
# Use this for .mp3 files, via ffmpeg. It will show the artist.
|
815
|
+
# === MultimediaParadise.loop_this_video
|
717
816
|
#
|
718
|
-
#
|
817
|
+
# This method can be used to loop a video, via ffmpeg.
|
719
818
|
#
|
720
|
-
#
|
819
|
+
# A commandline variant for this would look as follows:
|
721
820
|
#
|
722
|
-
#
|
723
|
-
# MultimediaParadise.show_artist('/Depot/Audio/Vivaldi_Concerto8.mp3')
|
821
|
+
# ffmpeg -stream_loop 3 -i Tata.webm -c copy output.webm
|
724
822
|
#
|
725
823
|
# ========================================================================= #
|
726
|
-
def self.
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
e "The artist is: #{simp(result)}"
|
736
|
-
end
|
737
|
-
end
|
738
|
-
|
739
|
-
# ========================================================================= #
|
740
|
-
# === MultimediaParadise.return_artist
|
741
|
-
# ========================================================================= #
|
742
|
-
def self.return_artist(
|
743
|
-
i,
|
744
|
-
report_classname = true
|
745
|
-
)
|
746
|
-
i = i.to_s
|
747
|
-
cmd =
|
748
|
-
'ffprobe -loglevel error -show_entries format_tags=artist '\
|
749
|
-
'-of default=noprint_wrappers=1:nokey=1 '+i
|
750
|
-
result = `#{cmd}`.chomp
|
824
|
+
def self.loop_this_video(this_video = 'foobar.webm', n_times = '5x')
|
825
|
+
result = []
|
826
|
+
[this_video].flatten.compact.each {|work_on_this_video_file|
|
827
|
+
n_times = n_times.to_s.delete('x').sub(/ times/,'')
|
828
|
+
output_file = "output_#{work_on_this_video_file}"
|
829
|
+
result << output_file
|
830
|
+
cmd = "ffmpeg -stream_loop #{n_times} -i #{work_on_this_video_file} -c copy #{output_file}"
|
831
|
+
esystem cmd
|
832
|
+
}
|
751
833
|
return result
|
752
834
|
end
|
753
835
|
|
754
836
|
# ========================================================================= #
|
755
|
-
# === MultimediaParadise.
|
756
|
-
# ========================================================================= #
|
757
|
-
def self.load_yaml(i)
|
758
|
-
YAML.load_file(i)
|
759
|
-
end
|
760
|
-
|
761
|
-
# ========================================================================= #
|
762
|
-
# === MultimediaParadise.open_yaml_file
|
763
|
-
#
|
764
|
-
# This will open my video collection.
|
837
|
+
# === MultimediaParadise.bin_dir?
|
765
838
|
# ========================================================================= #
|
766
|
-
def self.
|
767
|
-
|
768
|
-
|
769
|
-
esystem "bluefish #{i}"
|
770
|
-
end
|
839
|
+
def self.bin_dir?
|
840
|
+
RbConfig::CONFIG['bindir'].to_s+'/' # Ensure trailing '/'.
|
841
|
+
end; self.instance_eval { alias bindir? bin_dir? } # === MultimediaParadise.bindir?
|
771
842
|
|
772
843
|
# ========================================================================= #
|
773
|
-
# === MultimediaParadise.
|
844
|
+
# === MultimediaParadise.copy_bin_directory
|
774
845
|
#
|
775
|
-
# This
|
776
|
-
#
|
846
|
+
# This method can be used to copy the content of the bin/ directory
|
847
|
+
# onto the current working directory.
|
777
848
|
#
|
778
|
-
#
|
779
|
-
# ========================================================================= #
|
780
|
-
def self.flip_video_to_the_left(i)
|
781
|
-
ffmpeg_flip_video_to_the_left(i)
|
782
|
-
end
|
783
|
-
|
784
|
-
# ========================================================================= #
|
785
|
-
# === MultimediaParadise.flip_video_to_the_right
|
849
|
+
# Usage example from within ruby code:
|
786
850
|
#
|
787
|
-
#
|
788
|
-
# that is, to rotate it by +90 degrees.
|
789
|
-
# ========================================================================= #
|
790
|
-
def self.flip_video_to_the_right(i)
|
791
|
-
ffmpeg_flip_video_to_the_right(i)
|
792
|
-
end
|
793
|
-
|
794
|
-
# ========================================================================= #
|
795
|
-
# === glob
|
796
|
-
# ========================================================================= #
|
797
|
-
def glob(i)
|
798
|
-
Dir[i]
|
799
|
-
end
|
800
|
-
|
801
|
-
# ========================================================================= #
|
802
|
-
# === video_collection?
|
803
|
-
# ========================================================================= #
|
804
|
-
def video_collection?
|
805
|
-
::MultimediaParadise.file_video_collection
|
806
|
-
end
|
807
|
-
|
808
|
-
# ========================================================================= #
|
809
|
-
# === MultimediaParadise::PLAY_ZOOMED
|
851
|
+
# require 'multimedia_paradise'; MultimediaParadise.copy_bin_directory
|
810
852
|
#
|
811
|
-
# If this constant is set to true, then we will play in a zoomed way.
|
812
853
|
# ========================================================================= #
|
813
|
-
|
814
|
-
"#{
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
# =================================================================== #
|
843
|
-
when :TIT2
|
844
|
-
e 'The title is: '+
|
845
|
-
Colours.steelblue(value) unless value.empty?
|
846
|
-
# =================================================================== #
|
847
|
-
# === :TCON
|
848
|
-
#
|
849
|
-
# The genre.
|
850
|
-
# =================================================================== #
|
851
|
-
when :TCON
|
852
|
-
e 'The genre is: '+
|
853
|
-
Colours.steelblue(value) unless value.empty?
|
854
|
-
# =================================================================== #
|
855
|
-
# === :TYER
|
856
|
-
#
|
857
|
-
# The year.
|
858
|
-
# =================================================================== #
|
859
|
-
when :TYER
|
860
|
-
e 'The year is: '+
|
861
|
-
Colours.steelblue(value) unless value.empty?
|
862
|
-
# =================================================================== #
|
863
|
-
# === :TPE1
|
864
|
-
#
|
865
|
-
# The artist.
|
866
|
-
# =================================================================== #
|
867
|
-
when :TPE1
|
868
|
-
e 'The artist is: '+
|
869
|
-
Colours.steelblue(value) unless value.empty?
|
854
|
+
def self.copy_bin_directory
|
855
|
+
file_installed_binaries = "#{project_base_directory?}"\
|
856
|
+
"yaml/internal/installed_binaries.yml"
|
857
|
+
mkdir('bin/')
|
858
|
+
cd('bin/')
|
859
|
+
if File.exist? file_installed_binaries
|
860
|
+
e 'Making use of the file '+sfile(file_installed_binaries)+'.'
|
861
|
+
install_these_binaries = YAML.load_file(file_installed_binaries)
|
862
|
+
installation_directory = `gem env`.split("\n").select {|line| # Check for INSTALLATION DIRECTORY: /root/.gem
|
863
|
+
line.include? 'INSTALLATION DIRECTORY:'
|
864
|
+
}.first.
|
865
|
+
scan(/INSTALLATION DIRECTORY: (.+)$/).flatten.first
|
866
|
+
install_these_binaries.each {|entry|
|
867
|
+
target = installation_directory+'/bin/'+entry
|
868
|
+
if File.exist? target
|
869
|
+
e "Copying the file #{target} into the current working "\
|
870
|
+
"directory next."
|
871
|
+
copy_file(target, Dir.pwd)
|
872
|
+
else
|
873
|
+
# ================================================================= #
|
874
|
+
# Since as of January 2023 first try the bin_dir, before giving up.
|
875
|
+
# ================================================================= #
|
876
|
+
target = MultimediaParadise.bin_dir?+File.basename(entry)
|
877
|
+
if File.exist? target
|
878
|
+
e "Copying the file #{target} into the current working "\
|
879
|
+
"directory next."
|
880
|
+
copy_file(target, Dir.pwd)
|
881
|
+
else
|
882
|
+
no_file_exists_at(target)
|
870
883
|
end
|
871
|
-
|
872
|
-
|
873
|
-
end
|
884
|
+
end
|
885
|
+
}
|
874
886
|
end
|
875
887
|
end
|
876
888
|
|
877
889
|
# ========================================================================= #
|
878
|
-
# === MultimediaParadise.
|
879
|
-
# ========================================================================= #
|
880
|
-
def self.analyze_this_directory_for_id3_tags(i = Dir.pwd)
|
881
|
-
require 'id3lib'
|
882
|
-
all_files = Dir["#{i}/*.mp3"]
|
883
|
-
all_files.each {|this_mp3_file|
|
884
|
-
verbose_analyse_this_mp3_file_for_id3_tags(this_mp3_file)
|
885
|
-
}
|
886
|
-
end
|
887
|
-
|
888
|
-
# ========================================================================= #
|
889
|
-
# === MultimediaParadise.compress_this_ogg_file
|
890
|
+
# === MultimediaParadise.extract_one_image_per_second
|
890
891
|
#
|
891
|
-
# This method will
|
892
|
-
#
|
893
|
-
#
|
894
|
-
#
|
892
|
+
# This method will extract one-image-per-second from a given
|
893
|
+
# input video file.
|
894
|
+
#
|
895
|
+
# The first argument to this method should be the video file you
|
896
|
+
# are working with, such as 'foobar.mp4'.
|
895
897
|
# ========================================================================= #
|
896
|
-
def self.
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
898
|
+
def self.extract_one_image_per_second(
|
899
|
+
from_this_video_file = 'my_video.mpeg',
|
900
|
+
frame_size_to_use = '75x75'
|
901
|
+
)
|
902
|
+
extension_to_use = File.extname(from_this_video_file)
|
903
|
+
_ = 'ffmpeg -i '+from_this_video_file+
|
904
|
+
' -r 1 '+ # ← Specify the video-frame here, aka "1 image per second".
|
905
|
+
'-s '+frame_size_to_use+
|
906
|
+
' OUTPUT_'+from_this_video_file.sub(/#{extension_to_use}$/,'')+
|
907
|
+
extension_to_use
|
901
908
|
e
|
902
909
|
esystem _
|
903
910
|
e
|
904
911
|
end
|
905
912
|
|
906
|
-
# ========================================================================= #
|
907
|
-
# === MultimediaParadise.try_to_rename_kde_konsole_tab
|
908
|
-
# ========================================================================= #
|
909
|
-
def self.try_to_rename_kde_konsole_tab(
|
910
|
-
new_title = '_',
|
911
|
-
try_to_rename_the_kde_konsole_tab = TRY_TO_RENAME_THE_KDE_KONSOLE_TAB
|
912
|
-
)
|
913
|
-
if try_to_rename_the_kde_konsole_tab
|
914
|
-
begin
|
915
|
-
require 'roebe/requires/require_kde_konsole.rb'
|
916
|
-
rescue LoadError
|
917
|
-
e 'roebe/requires/require_kde_konsole.rb is not available'
|
918
|
-
end
|
919
|
-
if Object.const_defined?(:Roebe) and
|
920
|
-
Roebe.respond_to?(:rename_konsole)
|
921
|
-
Roebe.rename_konsole(new_title)
|
922
|
-
end
|
923
|
-
end
|
924
|
-
end; self.instance_eval { alias rename_kde_konsole try_to_rename_kde_konsole_tab } # === MultimediaParadise.rename_kde_konsole
|
925
|
-
self.instance_eval { alias do_rename_konsole try_to_rename_kde_konsole_tab } # === MultimediaParadise.do_rename_konsole
|
926
|
-
self.instance_eval { alias rename_kde_konsole_tab try_to_rename_kde_konsole_tab } # === MultimediaParadise.rename_kde_konsole_tab
|
927
|
-
|
928
|
-
# ========================================================================= #
|
929
|
-
# === MultimediaParadise.crop_this_video
|
930
|
-
#
|
931
|
-
# This method can be used to crop a particular video file, via
|
932
|
-
# ffmpeg.
|
933
|
-
#
|
934
|
-
# The raw ffmpeg-command would go like something like this:
|
935
|
-
#
|
936
|
-
# ffmpeg -i input.mp4 -filter:v "crop=out_w:out_h:x:y" output.mp4
|
937
|
-
#
|
938
|
-
# These variables are:
|
939
|
-
#
|
940
|
-
# → out_w is the width of the output rectangle
|
941
|
-
# → out_h is the height of the output rectangle
|
942
|
-
# → x and y specify the top left corner of the output rectangle
|
943
|
-
# → output.mp4 is the output file
|
944
|
-
#
|
945
|
-
# ========================================================================= #
|
946
|
-
def self.crop_this_video(
|
947
|
-
i = 'input.mp4',
|
948
|
-
output_file = 'output.mp4'
|
949
|
-
)
|
950
|
-
[i].flatten.compact.each {|this_video_file|
|
951
|
-
esystem 'ffmpeg -i '+
|
952
|
-
this_video_file.to_s+
|
953
|
-
' -filter:v "crop=w:h:x:y" '+
|
954
|
-
output_file.to_s
|
955
|
-
}
|
956
|
-
end
|
957
|
-
|
958
913
|
end
|
959
914
|
|
960
915
|
if __FILE__ == $PROGRAM_NAME
|
916
|
+
alias e puts
|
917
|
+
require 'multimedia_paradise/version/version.rb'
|
961
918
|
include MultimediaParadise
|
962
|
-
map_number_to_videofile
|
963
|
-
|
964
|
-
|
919
|
+
#map_number_to_videofile
|
920
|
+
e 'The version of the MultimediaParadise project is: '+
|
921
|
+
MultimediaParadise.version?
|
922
|
+
end # rb toplevel_methods.rb
|