From e005520ad86db62914f5f56908cbfedc1822538a Mon Sep 17 00:00:00 2001 From: evazion Date: Fri, 4 Nov 2022 17:01:11 -0500 Subject: [PATCH] media assets: save audio volume levels in media metadata. For videos with sound, save information about audio volume levels in the media asset's metadata. These values are stored: * FFmpeg:AudioPeakLoudness The peak loudness of the audio track, from 0.0 (silent) to 1.0 (max volume) * FFmpeg:AudioAverageLoudness The average loudness of the audio track, from 0.0 (silent) to 1.0 (max volume). * FFmpeg:AudioLoudnessRange The difference between the quietest and loudest sounds in the audio track (in decibels). * FFmpeg:AudioSilencePercentage The percentage of the video that is silent (1.0 is completely silent, 0.5 is 50% silence, 0.0 is no silence). These values are calculated based on the EBU R 128 standard, using the ffmpeg command below: ffmpeg -i file.mp4 -af silencedetect=duration=0.05:noise=0.0001,ebur128=metadata=1:peak=true:dualmono=true -f null /dev/null See the links below for details: * https://en.wikipedia.org/wiki/EBU_R_128 * https://www.ffmpeg.org/ffmpeg-filters.html#ebur128-1 * https://tech.ebu.ch/loudness * https://tech.ebu.ch/docs/tech/tech3341.pdf --- app/logical/ffmpeg.rb | 111 ++++++++++++++++++++++++- app/logical/media_file/video.rb | 9 +- test/files/mp4/test-silent-audio.mp4 | Bin 0 -> 22001 bytes test/files/webm/test-silent-audio.webm | Bin 0 -> 12786 bytes test/unit/media_file_test.rb | 53 +++++++++++- 5 files changed, 169 insertions(+), 4 deletions(-) create mode 100644 test/files/mp4/test-silent-audio.mp4 create mode 100644 test/files/webm/test-silent-audio.webm diff --git a/app/logical/ffmpeg.rb b/app/logical/ffmpeg.rb index 0ee773a29..2e9c56f66 100644 --- a/app/logical/ffmpeg.rb +++ b/app/logical/ffmpeg.rb @@ -140,10 +140,81 @@ class FFmpeg metadata[:streams].to_a.select { |stream| stream[:codec_type] == "audio" } end + # @return [Boolean] True if the file has an audio track. The audio track may be silent. def has_audio? audio_streams.present? end + # @return [Float, nil] The total duration in seconds of all silent sections of the audio track. + # Nil if the file doesn't have an audio track. + def silence_duration + playback_info[:silence].pluck("silence_duration").sum if has_audio? + end + + # @return [Float, nil] The percentage of the video that is silent, from 0% to 100%, or nil if the file doesn't + # have an audio track. If the silence percentage is 100%, then the audio track is totally silent. + def silence_percentage + return nil if !has_audio? || duration.to_f == 0.0 + (silence_duration.to_f / duration).clamp(0.0, 1.0).round(4) + end + + # The average loudness of the audio track, as a percentage of max volume. 0% is silent and 100% is max volume. + # + # The average loudness value ignores silent or quiet sections of the audio. 7% is the standard + # average loudness for TV programs. 15% to 30% is typical for music streaming services. + # + # @return [Float, nil] The average loudness as a percent, or nil if the file doesn't have an audio track. + # @see https://en.wikipedia.org/wiki/EBU_R_128 + def average_loudness + 10.pow(average_loudness_lufs / 20.0).round(4) if average_loudness_lufs.present? + end + + # The average loudness of the audio track, in LUFS units. -70.0 is silent and 0.0 is max volume. + # + # The average loudness value ignores silent or quiet sections of the audio. -23.0 LUFS is the + # standard average loudness for TV programs. -10.0 to -16.0 is typical for music streaming services. + # + # @return [Float, nil] The average loudness in LUFS, or nil if the file doesn't have an audio track. + # @see https://en.wikipedia.org/wiki/EBU_R_128 + def average_loudness_lufs + playback_info.dig(:ebur128, :I) if has_audio? + end + + # The loudness range of the audio track, in LU (loudness units, where 1 LU = 1 dB). The loudness + # range is roughly the difference between the quietest sound and the loudest sound (i.e., the + # dynamic range). A typical loudness range for music is around 5 to 10 LU. + # + # This is based on measuring loudness in 3-second intervals, ignoring silence, so it's not very + # meaningful for very short videos or videos that are mostly silent. + # + # @return [Float, nil] The loudness range in LU, or nil if the file doesn't have an audio track. + # @see https://en.wikipedia.org/wiki/EBU_R_128 + # @see https://tech.ebu.ch/docs/tech/tech3342.pdf (EBU Tech 3343 - Loudness Range: A Measure to Supplement EBU R 128 Loudness Normalization) + def loudness_range + playback_info.dig(:ebur128, :LRA) if has_audio? + end + + # The peak loudness of the audio track, as a percentage of max volume. 1.0 is 100% volume, 0.5 is + # 50% volume, 0.0 is 0% volume, etc. + # + # This is the true peak loudness, which means it measures the true loudness even if the audio is clipped. + # If the peak loudness if above 1.0, it means the audio is clipped. + # + # @return [Float, nil] The peak loudness in dBFS, or nil if the file doesn't have an audio track. + # @see https://en.wikipedia.org/wiki/EBU_R_128 + def peak_loudness + 10.pow(peak_loudness_dbfs / 20.0).round(4) if peak_loudness_dbfs.present? + end + + # The peak loudness of the audio track, in dBFS (decibels referenced to full scale). 0.0 is 100% + # volume, -6.0 is 50% volume, -20.0 is 10% volume, -40.0 is 1% volume, etc. + # + # @return [Float, nil] The peak loudness in dBFS, or nil if the file doesn't have an audio track. + # @see https://en.wikipedia.org/wiki/DBFS + def peak_loudness_dbfs + playback_info.dig(:ebur128, :Peak) if has_audio? + end + def packets metadata[:packets].to_a end @@ -178,8 +249,10 @@ class FFmpeg # Decode the full video and return a hash containing the frame count, fps, runtime, and the sizes of the decompressed video and audio streams. def playback_info + # https://ffmpeg.org/ffmpeg-filters.html#silencedetect + # https://ffmpeg.org/ffmpeg-filters.html#ebur128-1 # XXX `-c copy` is faster, but it doesn't decompress the stream so it can't detect corrupt videos. - output = shell!("ffmpeg -hide_banner -i #{file.path.shellescape} -f null /dev/null") + output = shell!("ffmpeg -hide_banner -i #{file.path.shellescape} -af silencedetect=noise=0.0001:duration=0.25s,ebur128=metadata=1:dualmono=true:peak=true -f null /dev/null") lines = output.split(/\r\n|\r|\n/) # time_line = "frame= 10 fps=0.0 q=-0.0 Lsize=N/A time=00:00:00.48 bitrate=N/A speed= 179x" @@ -195,7 +268,41 @@ class FFmpeg [key.strip, value.to_i * 1000] # [" audio", "16kB"] => ["audio", 16000] end.to_h - { **time_info, **size_info }.with_indifferent_access + # [silencedetect @ 0x561855af1040] silence_start: -0.00133333e=N/A speed= 25x + # [silencedetect @ 0x561855af1040] silence_end: 12.052 | silence_duration: 12.0533 + silence_info = lines.grep(/silence_duration/).map do |line| + line.scan(/[a-z_]+: *[0-9.]+/i).map do |pair| + key, value = pair.split(/: */) + [key, value.to_f] + end.to_h + end + + # [Parsed_ebur128_1 @ 0x5586b53889c0] Summary: + # + # Integrated loudness: + # I: -20.1 LUFS + # Threshold: -30.7 LUFS + # + # Loudness range: + # LRA: 5.8 LU + # Threshold: -40.6 LUFS + # LRA low: -24.0 LUFS + # LRA high: -18.2 LUFS + # + # True peak: + # Peak: -2.2 dBFS + ebur128_index = lines.rindex { |line| /Parsed_ebur128.*Summary:/ === line } + + if ebur128_index + ebur128_lines = lines[ebur128_index..ebur128_index + 13].join("\n") + ebur128_info = ebur128_lines.scan(/^ *[a-z ]+: *-?(?:inf|[0-9.]+) (?:LUFS|LU|dBFS)$/i).map do |pair| + key, value = pair.split(/: */) + value = -1000.0 if value == "-inf dBFS" # "Peak: -inf dBFS" for silent audio tracks. + [key.strip.tr(" ", "_"), value.to_f] # ["LRA low", "-34.3 LUFS"] => ["lra_low", -34.3] + end.to_h + end + + { **time_info, **size_info, silence: silence_info, ebur128: ebur128_info.to_h }.with_indifferent_access rescue Error => e { error: e.message.strip }.with_indifferent_access end diff --git a/app/logical/media_file/video.rb b/app/logical/media_file/video.rb index 4f08c8acd..615c88302 100644 --- a/app/logical/media_file/video.rb +++ b/app/logical/media_file/video.rb @@ -5,7 +5,10 @@ # # @see https://github.com/streamio/streamio-ffmpeg class MediaFile::Video < MediaFile - delegate :duration, :frame_count, :frame_rate, :has_audio?, :is_corrupt?, :major_brand, :pix_fmt, :video_codec, :video_bit_rate, :video_stream, :video_streams, :audio_codec, :audio_bit_rate, :audio_stream, :audio_streams, :error, to: :video + delegate :duration, :frame_count, :frame_rate, :has_audio?, :is_corrupt?, :major_brand, :pix_fmt, + :video_codec, :video_bit_rate, :video_stream, :video_streams, :audio_codec, :audio_bit_rate, + :audio_stream, :audio_streams, :silence_duration, :silence_percentage, :average_loudness, + :peak_loudness, :loudness_range, :error, to: :video def dimensions [video.width, video.height] @@ -28,6 +31,10 @@ class MediaFile::Video < MediaFile "FFmpeg:AudioProfile" => audio_stream[:profile], "FFmpeg:AudioLayout" => audio_stream[:channel_layout], "FFmpeg:AudioBitRate" => audio_bit_rate, + "FFmpeg:AudioPeakLoudness" => peak_loudness, + "FFmpeg:AudioAverageLoudness" => average_loudness, + "FFmpeg:AudioLoudnessRange" => loudness_range, + "FFmpeg:AudioSilencePercentage" => silence_percentage, }.compact_blank) end diff --git a/test/files/mp4/test-silent-audio.mp4 b/test/files/mp4/test-silent-audio.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..03b5b003c29b2d61b7055ec10cf6498a0891dc67 GIT binary patch literal 22001 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