Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails using stremio-ffmpeg gem to watermark a movie while uploading

I am using carrierwave to upload a movie to amazon s3 that works perfect.

Now I want to add a watermark to the movie while uploading or after uploading, I don't know, what's the best way?

I tried this:

movie_controller.rb action uploadVideo

movie = FFMPEG::Movie.new(@vid.video.url)

puts "........................................"
puts movie.inspect

if @vid.save

Just to find out if the video is catched from stremio.

But then I got the error that the movie is not found, the problem is that it doesn't look in the amazon s3 bucket, it looks on my local server

No such file or directory - the file '/uploads/tmp/1462954331-3471-8766/VID-20160424-WA0013.mp4' does not exist

What could be the solution? or should I do this in carrierwave uploader?

UPDATE:

When I do this after the .save action it looks at amazon s3 bucket .. but also says that the movie isn't there. But if I call it directly in browser it's displayed.

UPDATE Code:

#Laedt ein Video hoch
def uploadMovie
  @user = User.find_by_id session[:user_id]
  #Holt alle Channels für die er eine Berechtigung hat (Eingeloggter user)
  @user = User.find_by_id session[:user_id]
  @knowledgeproviderList = @user.knowledgeprovider
  @channels = Channel.where(knowledgeprovider_id:     @knowledgeproviderList.pluck(:id))
  @vid = Movie.new(movies_params)
  @channel = Channel.find(params[:vid][:channel_id])
  @vid.channel = @channel

  #Fügt dem Movie einen Tag hinzu
  createTag params
  createCategory params



  if @vid.save
    flash[:notice] = t("flash.saved")

    #movie = FFMPEG::Movie.new(@vid.video.url)

    #puts "........................................"
    #puts movie.inspect

    redirect_to :action => :add
   else
     redirect_to :action => :add
  end
 end

Update error:

movie = FFMPEG::Movie.new(@vid.video.current_path)

options = {watermark: "mages/header.png", resolution: "640x360", watermark_filter: { position: "RT", padding_x: 10, padding_y: 10 } }
movie.transcode("movie.flv", options)

enter image description here

Update: Added the code in the uploader:

  process :watermark_movie

     def watermark_movie
       if self.file.path
             options = {watermark: "images/header.png", resolution: "640x360", watermark_filter: { position: "RT", padding_x: 10, padding_y: 10 } }
             self.model.file = FFMPEG::Movie.new(self.file.path).transcode("#{root}/#{cache_dir}/#{self.cache_id}/file.mp4", options)
        end
      end

Error:

multi_json (1.12.0) lib/multi_json/adapter.rb:19:in `load'
multi_json (1.12.0) lib/multi_json.rb:122:in `load'
streamio-ffmpeg (2.0.0) lib/ffmpeg/movie.rb:28:in `initialize'
app/uploaders/movie_uploader.rb:40:in `new'
app/uploaders/movie_uploader.rb:40:in `watermark_movie'
carrierwave (0.11.2) lib/carrierwave/uploader/processing.rb:84:in `block in process!'
carrierwave (0.11.2) lib/carrierwave/uploader/processing.rb:76:in `each'
carrierwave (0.11.2) lib/carrierwave/uploader/processing.rb:76:in `process!'
carrierwave_backgrounder (0.4.2) lib/backgrounder/delay.rb:14:in `process!'
carrierwave (0.11.2) lib/carrierwave/uploader/callbacks.rb:18:in `block in with_callbacks'
carrierwave (0.11.2) lib/carrierwave/uploader/callbacks.rb:18:in `each'
carrierwave (0.11.2) lib/carrierwave/uploader/callbacks.rb:18:in `with_callbacks'
carrierwave (0.11.2) lib/carrierwave/uploader/cache.rb:134:in `cache!'
carrierwave (0.11.2) lib/carrierwave/mount.rb:329:in `cache'
carrierwave (0.11.2) lib/carrierwave/mount.rb:163:in `video='
carrierwave (0.11.2) lib/carrierwave/orm/activerecord.rb:39:in `video='
activerecord (4.2.1) lib/active_record/attribute_assignment.rb:54:in `public_send'
activerecord (4.2.1) lib/active_record/attribute_assignment.rb:54:in `_assign_attribute'
activerecord (4.2.1) lib/active_record/attribute_assignment.rb:41:in `block in assign_attributes'
actionpack (4.2.1) lib/action_controller/metal/strong_parameters.rb:183:in `each_pair'
actionpack (4.2.1) lib/action_controller/metal/strong_parameters.rb:183:in `each_pair'
activerecord (4.2.1) lib/active_record/attribute_assignment.rb:35:in `assign_attributes'
activerecord (4.2.1) lib/active_record/core.rb:559:in `init_attributes'
activerecord (4.2.1) lib/active_record/core.rb:281:in `initialize'
activerecord (4.2.1) lib/active_record/inheritance.rb:61:in `new'
activerecord (4.2.1) lib/active_record/inheritance.rb:61:in `new'
app/controllers/movies_controller.rb:71:in `uploadMovie'
actionpack (4.2.1) lib/action_controller/metal/implicit_render.rb:4:in `send_action'
actionpack (4.2.1) lib/abstract_controller/base.rb:198:in `process_action'
actionpack (4.2.1) lib/action_controller/metal/rendering.rb:10:in `process_action'
actionpack (4.2.1) lib/abstract_controller/callbacks.rb:20:in `block in process_action'
activesupport (4.2.1) lib/active_support/callbacks.rb:117:in `call'
activesupport (4.2.1) lib/active_support/callbacks.rb:117:in `call'
activesupport (4.2.1) lib/active_support/callbacks.rb:555:in `block (2 levels) in compile'
activesupport (4.2.1) lib/active_support/callbacks.rb:505:in `call'
activesupport (4.2.1) lib/active_support/callbacks.rb:505:in `call'
activesupport (4.2.1) lib/active_support/callbacks.rb:92:in `_run_callbacks'
activesupport (4.2.1) lib/active_support/callbacks.rb:776:in `_run_process_action_callbacks'
activesupport (4.2.1) lib/active_support/callbacks.rb:81:in `run_callbacks'
actionpack (4.2.1) lib/abstract_controller/callbacks.rb:19:in `process_action'
actionpack (4.2.1) lib/action_controller/metal/rescue.rb:29:in `process_action'
actionpack (4.2.1) lib/action_controller/metal/instrumentation.rb:32:in `block in process_action'
activesupport (4.2.1) lib/active_support/notifications.rb:164:in `block in instrument'
activesupport (4.2.1) lib/active_support/notifications/instrumenter.rb:20:in `instrument'
activesupport (4.2.1) lib/active_support/notifications.rb:164:in `instrument'
actionpack (4.2.1) lib/action_controller/metal/instrumentation.rb:30:in `process_action'
actionpack (4.2.1) lib/action_controller/metal/params_wrapper.rb:250:in `process_action'
activerecord (4.2.1) lib/active_record/railties/controller_runtime.rb:18:in `process_action'
actionpack (4.2.1) lib/abstract_controller/base.rb:137:in `process'
actionview (4.2.1) lib/action_view/rendering.rb:30:in `process'
actionpack (4.2.1) lib/action_controller/metal.rb:196:in `dispatch'
actionpack (4.2.1) lib/action_controller/metal/rack_delegation.rb:13:in `dispatch'
actionpack (4.2.1) lib/action_controller/metal.rb:237:in `block in action'
actionpack (4.2.1) lib/action_dispatch/routing/route_set.rb:74:in `call'
actionpack (4.2.1) lib/action_dispatch/routing/route_set.rb:74:in `dispatch'
actionpack (4.2.1) lib/action_dispatch/routing/route_set.rb:43:in `serve'
actionpack (4.2.1) lib/action_dispatch/journey/router.rb:43:in `block in serve'
actionpack (4.2.1) lib/action_dispatch/journey/router.rb:30:in `each'
actionpack (4.2.1) lib/action_dispatch/journey/router.rb:30:in `serve'
actionpack (4.2.1) lib/action_dispatch/routing/route_set.rb:819:in `call'
rack (1.6.4) lib/rack/etag.rb:24:in `call'
rack (1.6.4) lib/rack/conditionalget.rb:38:in `call'
rack (1.6.4) lib/rack/head.rb:13:in `call'
actionpack (4.2.1) lib/action_dispatch/middleware/params_parser.rb:27:in `call'
actionpack (4.2.1) lib/action_dispatch/middleware/flash.rb:260:in `call'
rack (1.6.4) lib/rack/session/abstract/id.rb:225:in `context'
rack (1.6.4) lib/rack/session/abstract/id.rb:220:in `call'
actionpack (4.2.1) lib/action_dispatch/middleware/cookies.rb:560:in `call'
activerecord (4.2.1) lib/active_record/query_cache.rb:36:in `call'
activerecord (4.2.1) lib/active_record/connection_adapters/abstract/connection_pool.rb:649:in `call'
activerecord (4.2.1) lib/active_record/migration.rb:378:in `call'
actionpack (4.2.1) lib/action_dispatch/middleware/callbacks.rb:29:in `block in call'
activesupport (4.2.1) lib/active_support/callbacks.rb:88:in `call'
activesupport (4.2.1) lib/active_support/callbacks.rb:88:in `_run_callbacks'
activesupport (4.2.1) lib/active_support/callbacks.rb:776:in `_run_call_callbacks'
activesupport (4.2.1) lib/active_support/callbacks.rb:81:in `run_callbacks'
actionpack (4.2.1) lib/action_dispatch/middleware/callbacks.rb:27:in `call'
actionpack (4.2.1) lib/action_dispatch/middleware/reloader.rb:73:in `call'
actionpack (4.2.1) lib/action_dispatch/middleware/remote_ip.rb:78:in `call'
actionpack (4.2.1) lib/action_dispatch/middleware/debug_exceptions.rb:17:in `call'
web-console (2.3.0) lib/web_console/middleware.rb:20:in `block in call'
web-console (2.3.0) lib/web_console/middleware.rb:18:in `catch'
web-console (2.3.0) lib/web_console/middleware.rb:18:in `call'
actionpack (4.2.1) lib/action_dispatch/middleware/show_exceptions.rb:30:in `call'
railties (4.2.1) lib/rails/rack/logger.rb:38:in `call_app'
railties (4.2.1) lib/rails/rack/logger.rb:20:in `block in call'
activesupport (4.2.1) lib/active_support/tagged_logging.rb:68:in `block in tagged'
activesupport (4.2.1) lib/active_support/tagged_logging.rb:26:in `tagged'
activesupport (4.2.1) lib/active_support/tagged_logging.rb:68:in `tagged'
railties (4.2.1) lib/rails/rack/logger.rb:20:in `call'
actionpack (4.2.1) lib/action_dispatch/middleware/request_id.rb:21:in `call'
rack (1.6.4) lib/rack/methodoverride.rb:22:in `call'
rack (1.6.4) lib/rack/runtime.rb:18:in `call'
activesupport (4.2.1) lib/active_support/cache/strategy/local_cache_middleware.rb:28:in `call'
rack (1.6.4) lib/rack/lock.rb:17:in `call'
actionpack (4.2.1) lib/action_dispatch/middleware/static.rb:113:in `call'
rack (1.6.4) lib/rack/sendfile.rb:113:in `call'
railties (4.2.1) lib/rails/engine.rb:518:in `call'
railties (4.2.1) lib/rails/application.rb:164:in `call'
rack (1.6.4) lib/rack/lock.rb:17:in `call'
rack (1.6.4) lib/rack/content_length.rb:15:in `call'
rack (1.6.4) lib/rack/handler/webrick.rb:88:in `service'
/home/felix/.rvm/rubies/ruby-2.0.0-p643/lib/ruby/2.0.0/webrick/httpserver.rb:138:in `service'
/home/felix/.rvm/rubies/ruby-2.0.0-p643/lib/ruby/2.0.0/webrick/httpserver.rb:94:in `run'
/home/felix/.rvm/rubies/ruby-2.0.0-p643/lib/ruby/2.0.0/webrick/server.rb:295:in `block in start_thread'

UPDATE -- Movie Uploader

# encoding: utf-8
class MovieUploader < CarrierWave::Uploader::Base

  # Include RMagick or MiniMagick support:
  # include CarrierWave::RMagick
  include CarrierWave::MiniMagick
  include CarrierWave::Video
  include CarrierWave::Video::Thumbnailer
  include CarrierWave::Backgrounder::Delay

  require 'rubygems'
  require 'streamio-ffmpeg'

  # Choose what kind of storage to use for this uploader:
  storage :fog

  # Override the directory where uploaded files will be stored.
  # This is a sensible default for uploaders that are meant to be mounted:
  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end

  process :watermark_movie

  def watermark_movie
    puts "ssssssssssssssssssssssssssssssssss"
    puts self.file.inspect

    if self.file.path
      options = {watermark: "http://felix-hohlwegler.de/holz-soft/include/designs/design13/images/header.png", resolution: "640x360", watermark_filter: { position: "RT", padding_x: 10, padding_y: 10 } }
      self.model.file = FFMPEG::Movie.new(self.file.path).transcode("#{root}/#{cache_dir}/#{self.cache_id}/file.mp4", options)
    end
  end

  version :thumb do
    process thumbnail: [{format: 'png', quality: 10, size: 1200, strip: false, seek: 10, logger: Rails.logger}]
    def full_filename for_file
      png_name for_file, version_name
    end
  end

  def png_name for_file, version_name
    %Q{#{version_name}_#{for_file.chomp(File.extname(for_file))}.png}
  end


  # Add a white list of extensions which are allowed to be uploaded.
  # For images you might use something like this:
   def extension_white_list
     %w(mov avi mkv mpeg mpeg2 mp4 3gp)
   end
end
like image 498
Felix Avatar asked May 11 '16 08:05

Felix


3 Answers

We do something similar in our application that deals with audio. Obviously, we do not use video or watermarking but we use streamio-ffmpeg to do some transcoding of sorts.

Instead of doing code in the controller related to the watermark, why not instead move that functionality to the uploader. For example, our convert_to_mp3 method could be your watermarking method. Seems like this would potentially solve your problem.

# encoding: utf-8
require 'streamio-ffmpeg'

class FileUploader < CarrierWave::Uploader::Base

  # Choose what kind of storage to use for this uploader:
  storage :fog

  before :store, :remember_cache_id
  after :store, :delete_tmp_dir

  # Override the directory where uploaded files will be stored.
  # This is a sensible default for uploaders that are meant to be mounted:
  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end

  # Process files as they are uploaded:
  process :convert_to_mp3

  def convert_to_mp3
    if self.file.path
      if self.file.extension == 'm4a' || self.file.extension == 'wav' || self.file.extension == 'aac'
        self.model.file = FFMPEG::Movie.new(self.file.path).transcode("#{root}/#{cache_dir}/#{self.cache_id}/file.mp3", options_string)
      end
    end
  end

  def options_string
    if self.file.extension == 'm4a'
      "-acodec libmp3lame -write_xing 0"
    elsif self.file.extension == 'aac'
      "-acodec libmp3lame -write_xing 0"
    elsif self.file.extension == 'wav'
      "-acodec libmp3lame -write_xing 0"
    end
  end


  # Add a white list of extensions which are allowed to be uploaded.
  # For images you might use something like this:
  def extension_white_list
    %w(mp3 m4a wav)
  end

  def cache_id
    @cache_id
  end

  def remember_cache_id(new_file)
    @cache_id_was = cache_id
  end

  def delete_tmp_dir(new_file)
    # make sure we don't delete other things accidentally by checking the name pattern
    if @cache_id_was.present? && @cache_id_was =~ /\A[\d]{8}\-[\d]{4}\-[\d]+\-[\d]{4}\z/
      FileUtils.rm_rf(File.join(root, cache_dir, @cache_id_was))
    end
  end

end
like image 99
Kyle Avatar answered Oct 14 '22 02:10

Kyle


From the CarrierWave docs:

CarrierWave gives you a store for permanent storage, and a cache for temporary storage. You can use different stores, including filesystem and cloud storage.

and

...you can cache files by assigning to the attribute, they will automatically be stored when the record is saved.

Assuming that you've mounted your uploader to the video column of your model, (e.g - mount_uploader :video, VideoUploader) calling video.url will return the cache path after you assign a value to video column. After you save the model, the url method will look in the store path.

In your case, calling @vid.video.store_path will tell ffmpeg to look at your S3 bucket - however, it's best to familiarize yourself with the cache and store path, because watermarking may be more performant on the local, cached version of the file.


like image 3
kspector Avatar answered Oct 14 '22 04:10

kspector


With Kyle together we figured out that the following is required

only version 1.0.0 works fine

gem 'streamio-ffmpeg', '1.0.0'

The function is now in the carrierwave uploader and looks like this:

  process :watermark_movie

  def watermark_movie
      options = {watermark: "#{Rails.root}/public/images/logo_klein.png", resolution: "640x360", watermark_filter: {position: "RT", padding_x: 10, padding_y: 10},custom: '-strict experimental'}
      #debugger
      tmp_path = File.join File.dirname(current_path), "tmp_file.mp4"
      file = FFMPEG::Movie.new(self.file.path)
      file.transcode tmp_path, options
      File.rename tmp_path, current_path
  end

At the Moment there are no more errors, problem is still that the watermark is not working.

Update:

A working solution is:

system "ffmpeg -i #{self.file.path} -vf 'movie=#{watermarkimage} [watermark]; [in][watermark] overlay=main_w-overlay_w-10:10 [out]' -strict experimental #{tmp_path}"
like image 2
Felix Avatar answered Oct 14 '22 04:10

Felix