From 540a3e111afef3f744436bb9c347d0ff151a7843 Mon Sep 17 00:00:00 2001 From: evazion Date: Sun, 5 Sep 2021 06:53:10 -0500 Subject: [PATCH] Replace streamio-ffmpeg library. Replace the streamio-ffmpeg library with our own very thin FFmpeg wrapper. --- Gemfile | 1 - Gemfile.lock | 3 -- app/logical/ffmpeg.rb | 55 ++++++++++++++++++++++++++++++-- app/logical/media_file/video.rb | 16 +++------- config/initializers/ffmpeg.rb | 3 -- test/files/test-audio.mp4 | Bin 0 -> 54082 bytes test/unit/media_file_test.rb | 7 ++++ 7 files changed, 63 insertions(+), 22 deletions(-) delete mode 100644 config/initializers/ffmpeg.rb create mode 100644 test/files/test-audio.mp4 diff --git a/Gemfile b/Gemfile index 8c36b3e87..3ce5dafd9 100644 --- a/Gemfile +++ b/Gemfile @@ -16,7 +16,6 @@ gem 'bcrypt', :require => "bcrypt" gem 'capistrano', '~> 3.10' gem 'capistrano-rails' gem 'capistrano-rbenv' -gem 'streamio-ffmpeg' gem 'rubyzip', :require => "zip" gem 'stripe' gem 'aws-sdk-sqs', '~> 1' diff --git a/Gemfile.lock b/Gemfile.lock index 07dd95424..8be564ad3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -458,8 +458,6 @@ GEM net-scp (>= 1.1.2) net-ssh (>= 2.8.0) stackprof (0.2.17) - streamio-ffmpeg (3.0.2) - multi_json (~> 1.8) stripe (5.38.0) stripe-ruby-mock (3.0.1) dante (>= 0.2.0) @@ -580,7 +578,6 @@ DEPENDENCIES simplecov solargraph stackprof - streamio-ffmpeg stripe stripe-ruby-mock terminal-table diff --git a/app/logical/ffmpeg.rb b/app/logical/ffmpeg.rb index 24f30045c..fa8a1fa0a 100644 --- a/app/logical/ffmpeg.rb +++ b/app/logical/ffmpeg.rb @@ -1,4 +1,11 @@ +require "shellwords" + +# A wrapper for the ffmpeg command. class FFmpeg + extend Memoist + + class Error < StandardError; end + attr_reader :file # Operate on a file with FFmpeg. @@ -16,10 +23,52 @@ class FFmpeg # https://ffmpeg.org/ffmpeg.html#Main-options # https://ffmpeg.org/ffmpeg-filters.html#thumbnail - ffmpeg_out, status = Open3.capture2e("ffmpeg -i #{file.path} -vf thumbnail=300 -frames:v 1 -y #{vp.path}") - raise "ffmpeg failed: #{ffmpeg_out}" if !status.success? - Rails.logger.debug(ffmpeg_out) + output = shell!("ffmpeg -i #{file.path.shellescape} -vf thumbnail=300 -frames:v 1 -y #{vp.path.shellescape}") + Rails.logger.debug(output) MediaFile.open(vp) end + + # Get file metadata using ffprobe. + # @see https://ffmpeg.org/ffprobe.html + # @see https://gist.github.com/nrk/2286511 + # @return [Hash] a hash of the file's metadata + def metadata + output = shell!("ffprobe -v quiet -print_format json -show_format -show_streams #{file.path.shellescape}") + json = JSON.parse(output) + json.with_indifferent_access + end + + def width + video_channels.first[:width] + end + + def height + video_channels.first[:height] + end + + def duration + metadata.dig(:format, :duration).to_f + end + + def video_channels + metadata[:streams].select { |stream| stream[:codec_type] == "video" } + end + + def audio_channels + metadata[:streams].select { |stream| stream[:codec_type] == "audio" } + end + + def has_audio? + audio_channels.present? + end + + def shell!(command) + program = command.shellsplit.first + output, status = Open3.capture2e(command) + raise Error, "#{program} failed: #{output}" if !status.success? + output + end + + memoize :metadata end diff --git a/app/logical/media_file/video.rb b/app/logical/media_file/video.rb index 13afbd7fb..b981c432e 100644 --- a/app/logical/media_file/video.rb +++ b/app/logical/media_file/video.rb @@ -3,14 +3,12 @@ # # @see https://github.com/streamio/streamio-ffmpeg class MediaFile::Video < MediaFile + delegate :duration, :has_audio?, to: :video + def dimensions [video.width, video.height] end - def duration - video.duration - end - def preview(max_width, max_height) preview_frame.preview(max_width, max_height) end @@ -19,20 +17,14 @@ class MediaFile::Video < MediaFile preview_frame.crop(max_width, max_height) end - def has_audio? - video.audio_channels.present? - end - private def video - raise NotImplementedError, "can't process videos: ffmpeg or mkvmerge not installed" unless self.class.videos_enabled? - - FFMPEG::Movie.new(file.path) + FFmpeg.new(file) end def preview_frame - FFmpeg.new(file).smart_video_preview + video.smart_video_preview end memoize :video, :preview_frame, :dimensions, :duration, :has_audio? diff --git a/config/initializers/ffmpeg.rb b/config/initializers/ffmpeg.rb deleted file mode 100644 index 387508f8c..000000000 --- a/config/initializers/ffmpeg.rb +++ /dev/null @@ -1,3 +0,0 @@ -unless Rails.env.development? - FFMPEG.logger.level = Logger::ERROR -end diff --git a/test/files/test-audio.mp4 b/test/files/test-audio.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..dbfae20bbed85540600064e54e614eb5549f2cec GIT binary patch literal 54082 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 jvDcIr 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 W0|1nUAU6G@NfleDP$))WpaKB=zgXJ< literal 0 HcmV?d00001 diff --git a/test/unit/media_file_test.rb b/test/unit/media_file_test.rb index b45d055e9..ff0d6345d 100644 --- a/test/unit/media_file_test.rb +++ b/test/unit/media_file_test.rb @@ -170,4 +170,11 @@ class MediaFileTest < ActiveSupport::TestCase assert_equal([60, 60], webm.dimensions) end end + + context "for a video" do + should "detect videos with audio" do + assert_equal(true, MediaFile.open("test/files/test-audio.mp4").has_audio?) + assert_equal(false, MediaFile.open("test/files/test-300x300.mp4").has_audio?) + end + end end