about summary refs log tree commit diff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/lib/video_metadata_extractor.rb54
-rw-r--r--app/models/media_attachment.rb4
2 files changed, 56 insertions, 2 deletions
diff --git a/app/lib/video_metadata_extractor.rb b/app/lib/video_metadata_extractor.rb
new file mode 100644
index 000000000..03e40f923
--- /dev/null
+++ b/app/lib/video_metadata_extractor.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+class VideoMetadataExtractor
+  attr_reader :duration, :bitrate, :video_codec, :audio_codec,
+              :colorspace, :width, :height, :frame_rate
+
+  def initialize(path)
+    @path     = path
+    @metadata = Oj.load(ffmpeg_command_output, mode: :strict, symbol_keys: true)
+
+    parse_metadata
+  rescue Terrapin::ExitStatusError, Oj::ParseError
+    @invalid = true
+  rescue Terrapin::CommandNotFoundError
+    raise Paperclip::Errors::CommandNotFoundError, 'Could not run the `ffprobe` command. Please install ffmpeg.'
+  end
+
+  def valid?
+    !@invalid
+  end
+
+  private
+
+  def ffmpeg_command_output
+    command = Terrapin::CommandLine.new('ffprobe', '-i :path -print_format :format -show_format -show_streams -show_error -loglevel :loglevel')
+    command.run(path: @path, format: 'json', loglevel: 'fatal')
+  end
+
+  def parse_metadata
+    if @metadata.key?(:format)
+      @duration = @metadata[:format][:duration].to_f
+      @bitrate  = @metadata[:format][:bit_rate].to_i
+    end
+
+    if @metadata.key?(:streams)
+      video_streams = @metadata[:streams].select { |stream| stream[:codec_type] == 'video' }
+      audio_streams = @metadata[:streams].select { |stream| stream[:codec_type] == 'audio' }
+
+      if (video_stream = video_streams.first)
+        @video_codec = video_stream[:codec_name]
+        @colorspace  = video_stream[:pix_fmt]
+        @width       = video_stream[:width]
+        @height      = video_stream[:height]
+        @frame_rate  = video_stream[:avg_frame_rate] == '0/0' ? nil : Rational(video_stream[:avg_frame_rate])
+      end
+
+      if (audio_stream = audio_streams.first)
+        @audio_codec = audio_stream[:codec_name]
+      end
+    end
+
+    @invalid = true if @metadata.key?(:error)
+  end
+end
diff --git a/app/models/media_attachment.rb b/app/models/media_attachment.rb
index 5cf4d8127..3515f6895 100644
--- a/app/models/media_attachment.rb
+++ b/app/models/media_attachment.rb
@@ -287,7 +287,7 @@ class MediaAttachment < ApplicationRecord
       if instance.file_content_type == 'image/gif'
         [:gif_transcoder, :blurhash_transcoder]
       elsif VIDEO_MIME_TYPES.include?(instance.file_content_type)
-        [:video_transcoder, :blurhash_transcoder, :type_corrector]
+        [:transcoder, :blurhash_transcoder, :type_corrector]
       elsif AUDIO_MIME_TYPES.include?(instance.file_content_type)
         [:image_extractor, :transcoder, :type_corrector]
       else
@@ -388,7 +388,7 @@ class MediaAttachment < ApplicationRecord
   # paths but ultimately the same file, so it makes sense to memoize the
   # result while disregarding the path
   def ffmpeg_data(path = nil)
-    @ffmpeg_data ||= FFMPEG::Movie.new(path)
+    @ffmpeg_data ||= VideoMetadataExtractor.new(path)
   end
 
   def enqueue_processing