From f2bda44d7627ba879797d4f143ee7f9fa0db80fb Mon Sep 17 00:00:00 2001 From: Matt Date: Sat, 17 Aug 2013 11:55:23 -0300 Subject: [PATCH 1/2] Add support for multiple inputs --- lib/ffmpeg/encoding_options.rb | 4 ++++ lib/ffmpeg/movie.rb | 22 ++++++++++++++++------ lib/ffmpeg/transcoder.rb | 9 +++++++-- spec/ffmpeg/movie_spec.rb | 2 +- 4 files changed, 28 insertions(+), 9 deletions(-) diff --git a/lib/ffmpeg/encoding_options.rb b/lib/ffmpeg/encoding_options.rb index 10137dbc..dac46b89 100644 --- a/lib/ffmpeg/encoding_options.rb +++ b/lib/ffmpeg/encoding_options.rb @@ -136,6 +136,10 @@ def convert_x264_preset(value) "-preset #{value}" end + def convert_deinterlace(value) + value ? "-filter:v #{value}" : "" + end + def convert_custom(value) value end diff --git a/lib/ffmpeg/movie.rb b/lib/ffmpeg/movie.rb index db96ae76..29505552 100644 --- a/lib/ffmpeg/movie.rb +++ b/lib/ffmpeg/movie.rb @@ -2,18 +2,24 @@ module FFMPEG class Movie - attr_reader :path, :duration, :time, :bitrate, :rotation, :creation_time + attr_reader :paths, :duration, :time, :bitrate, :rotation, :creation_time attr_reader :video_stream, :video_codec, :video_bitrate, :colorspace, :resolution, :dar attr_reader :audio_stream, :audio_codec, :audio_bitrate, :audio_sample_rate attr_reader :container - def initialize(path) - raise Errno::ENOENT, "the file '#{path}' does not exist" unless File.exists?(path) + def initialize(paths) + paths = [paths] unless paths.is_a? Array - @path = path + inputs = [] + paths.each do |path| + raise Errno::ENOENT, "the file '#{path}' does not exist" unless File.exists?(path) + inputs.push "-i #{Shellwords.escape(path)}" + end + + @paths = paths # ffmpeg will output to stderr - command = "#{FFMPEG.ffmpeg_binary} -i #{Shellwords.escape(path)}" + command = "#{FFMPEG.ffmpeg_binary} #{inputs.join " "}" output = Open3.popen3(command) { |stdin, stdout, stderr| stderr.read } fix_encoding(output) @@ -77,7 +83,11 @@ def calculated_aspect_ratio end def size - File.size(@path) + size = 0 + @paths.each do |path| + size += File.size(path) + end + size end def audio_channels diff --git a/lib/ffmpeg/transcoder.rb b/lib/ffmpeg/transcoder.rb index 1d27f899..34964c7e 100644 --- a/lib/ffmpeg/transcoder.rb +++ b/lib/ffmpeg/transcoder.rb @@ -54,7 +54,12 @@ def encoded private # frame= 4855 fps= 46 q=31.0 size= 45306kB time=00:02:42.28 bitrate=2287.0kbits/ def transcode_movie - @command = "#{FFMPEG.ffmpeg_binary} -y -i #{Shellwords.escape(@movie.path)} #{@raw_options} #{Shellwords.escape(@output_file)}" + inputs = [] + @movie.paths.each do |path| + inputs.push "-i #{Shellwords.escape(path)}" + end + + @command = "#{FFMPEG.ffmpeg_binary} -y #{inputs.join " "} #{@raw_options} #{Shellwords.escape(@output_file)}" FFMPEG.logger.info("Running transcoding...\n#{@command}\n") @output = "" @@ -91,7 +96,7 @@ def transcode_movie def validate_output_file(&block) if encoding_succeeded? yield(1.0) if block_given? - FFMPEG.logger.info "Transcoding of #{@movie.path} to #{@output_file} succeeded\n" + FFMPEG.logger.info "Transcoding of #{@movie.paths.join ", "} to #{@output_file} succeeded\n" else errors = "Errors: #{@errors.join(", ")}. " FFMPEG.logger.error "Failed encoding...\n#{@command}\n\n#{@output}\n#{errors}\n" diff --git a/spec/ffmpeg/movie_spec.rb b/spec/ffmpeg/movie_spec.rb index 0054b63f..6cb4b774 100644 --- a/spec/ffmpeg/movie_spec.rb +++ b/spec/ffmpeg/movie_spec.rb @@ -150,7 +150,7 @@ module FFMPEG end it "should remember the movie path" do - @movie.path.should == "#{fixture_path}/movies/awesome movie.mov" + @movie.paths.should == ["#{fixture_path}/movies/awesome movie.mov"] end it "should parse duration to number of seconds" do From dd91ede93309f44fcecaf4e5807d994b161eab71 Mon Sep 17 00:00:00 2001 From: Matt Date: Sat, 17 Aug 2013 17:50:09 -0300 Subject: [PATCH 2/2] Fixed some bugs, now bash is used to pass multiple inputs --- lib/ffmpeg/encoding_options.rb | 4 ++++ lib/ffmpeg/movie.rb | 8 +++++--- lib/ffmpeg/transcoder.rb | 17 +++++++++-------- lib/ffmpeg/version.rb | 2 +- spec/ffmpeg/transcoder_spec.rb | 4 ++-- 5 files changed, 21 insertions(+), 14 deletions(-) diff --git a/lib/ffmpeg/encoding_options.rb b/lib/ffmpeg/encoding_options.rb index dac46b89..a12df763 100644 --- a/lib/ffmpeg/encoding_options.rb +++ b/lib/ffmpeg/encoding_options.rb @@ -136,6 +136,10 @@ def convert_x264_preset(value) "-preset #{value}" end + def convert_scale(value) + value ? "-filter:v scale=#{value}" : "" + end + def convert_deinterlace(value) value ? "-filter:v #{value}" : "" end diff --git a/lib/ffmpeg/movie.rb b/lib/ffmpeg/movie.rb index 29505552..7402cea8 100644 --- a/lib/ffmpeg/movie.rb +++ b/lib/ffmpeg/movie.rb @@ -13,15 +13,17 @@ def initialize(paths) inputs = [] paths.each do |path| raise Errno::ENOENT, "the file '#{path}' does not exist" unless File.exists?(path) - inputs.push "-i #{Shellwords.escape(path)}" + inputs.push Shellwords.escape(path) end @paths = paths # ffmpeg will output to stderr - command = "#{FFMPEG.ffmpeg_binary} #{inputs.join " "}" - output = Open3.popen3(command) { |stdin, stdout, stderr| stderr.read } + source = (inputs.length > 1) ? "-f concat -i <(printf 'file %s\n' #{inputs.join " "})" : "-i #{inputs.first}" + command = "#{FFMPEG.ffmpeg_binary} #{source}" + command = "/bin/bash -c \"#{command}\"" + output = Open3.popen3(command) { |stdin, stdout, stderr| stderr.read } fix_encoding(output) output[/Input \#\d+\,\s*(\S+),\s*from/] diff --git a/lib/ffmpeg/transcoder.rb b/lib/ffmpeg/transcoder.rb index 34964c7e..59a6721a 100644 --- a/lib/ffmpeg/transcoder.rb +++ b/lib/ffmpeg/transcoder.rb @@ -54,18 +54,18 @@ def encoded private # frame= 4855 fps= 46 q=31.0 size= 45306kB time=00:02:42.28 bitrate=2287.0kbits/ def transcode_movie - inputs = [] - @movie.paths.each do |path| - inputs.push "-i #{Shellwords.escape(path)}" - end + inputs = @movie.paths.map {|path| Shellwords.escape(path)} + source = (inputs.length > 1) ? "-f concat -i <(printf 'file %s\n' #{inputs.join " "})" : "-i #{inputs.first}" + + @command = "#{FFMPEG.ffmpeg_binary} -y #{source} #{@raw_options} #{Shellwords.escape(@output_file)}" + @command = "/bin/bash -c \"#{@command}\"" - @command = "#{FFMPEG.ffmpeg_binary} -y #{inputs.join " "} #{@raw_options} #{Shellwords.escape(@output_file)}" FFMPEG.logger.info("Running transcoding...\n#{@command}\n") @output = "" Open3.popen3(@command) do |stdin, stdout, stderr, wait_thr| begin - yield(0.0) if block_given? + #yield([0.0, "00:00:00.00"]) if block_given? # the progress could be unknown in case multiple inputs are used next_line = Proc.new do |line| fix_encoding(line) @output << line @@ -75,8 +75,9 @@ def transcode_movie else # better make sure it wont blow up in case of unexpected output time = 0.0 end + processed = "#{$1}:#{$2}:#{$3}" progress = time / @movie.duration - yield(progress) if block_given? + yield([progress, processed]) if block_given? end end @@ -95,7 +96,7 @@ def transcode_movie def validate_output_file(&block) if encoding_succeeded? - yield(1.0) if block_given? + #yield(1.0) if block_given? # the progress could be unknown in case multiple inputs are used FFMPEG.logger.info "Transcoding of #{@movie.paths.join ", "} to #{@output_file} succeeded\n" else errors = "Errors: #{@errors.join(", ")}. " diff --git a/lib/ffmpeg/version.rb b/lib/ffmpeg/version.rb index d7200442..ef8b7423 100644 --- a/lib/ffmpeg/version.rb +++ b/lib/ffmpeg/version.rb @@ -1,3 +1,3 @@ module FFMPEG - VERSION = "1.0.0" + VERSION = "1.0.2" end diff --git a/spec/ffmpeg/transcoder_spec.rb b/spec/ffmpeg/transcoder_spec.rb index 82f7fa3a..fba07f1c 100644 --- a/spec/ffmpeg/transcoder_spec.rb +++ b/spec/ffmpeg/transcoder_spec.rb @@ -72,8 +72,8 @@ module FFMPEG progress_updates = [] transcoder.run { |progress| progress_updates << progress } transcoder.encoded.should be_valid - progress_updates.should include(0.0, 1.0) - progress_updates.length.should >= 3 + progress_updates.flatten.should include("00:00:07.58") + progress_updates.flatten.length.should >= 1 File.exists?("#{tmp_path}/awesome.flv").should be_true end