av 0.0.6 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7fba45a60d49e120bdaf9d2e27d2b6a82353f35e
4
- data.tar.gz: 06a7fc08a643988726ce5ac463f6758cd27e69f4
3
+ metadata.gz: c457580a1a913b757c7451679a5ee05779b1e180
4
+ data.tar.gz: 789e34475f417dbf0371f7bc2bc6e7ec2ac655fa
5
5
  SHA512:
6
- metadata.gz: d6b7f5ffc96ca1dc66bd591b440381e253045d506cb17b51c90791b073bc124865e27b0c6879ad914839891848bda7fd3a095a3741a11d5a03caaa8077cfe0c1
7
- data.tar.gz: 8e2f30438d202dcf0da6c80bfded898d83fd357f3c8040b01ad11d84ebb6ab52222fc894ad17b3beff4741a70812ad52e0daa89b08307fdf0459486ff2a24ce0
6
+ metadata.gz: 80d293f42ba494f35559df9f09a914cd59d60036be5e95ce83e2c906d07eafeacd3c78e17bb814797931984a58ecc78e3538923fd7dbb46b8f58e96bca90aebc
7
+ data.tar.gz: 2e5e1d55dbd04928f20a282115a8afe217e1cfb93175c610b1c585393f6cbefa8e9a6db412bbf976753da0053952b11e9ef213ff97abdd0a899a72462f019391
data/lib/av.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require "av/version"
2
2
  require "av/exceptions"
3
3
  require "av/cli"
4
+ require "av/param_hash"
4
5
  require "av/commands/ffmpeg"
5
6
  require "av/commands/avconv"
6
7
  require "cocaine"
@@ -8,17 +9,12 @@ require "cocaine"
8
9
  module Av
9
10
  extend self
10
11
 
11
- def cli
12
- ::Av::Cli.new
13
- end
14
-
15
- def quiet
16
- return @quiet if @quiet
17
- true
12
+ def cli(options = {})
13
+ ::Av::Cli.new(options)
18
14
  end
19
15
 
20
16
  def run line, codes = [0]
21
- Av.log("Running command: #{line}")
17
+ ::Av.log("Running command: #{line}")
22
18
  begin
23
19
  Cocaine::CommandLine.new(line, "", expected_outcodes: codes).run
24
20
  rescue Cocaine::ExitStatusError => e
@@ -29,15 +25,4 @@ module Av
29
25
  def log message
30
26
  puts "[AV] #{message}"
31
27
  end
32
-
33
- def detect_command(command)
34
- command = "if command -v #{command} 2>/dev/null; then echo \"true\"; else echo \"false\"; fi"
35
- result = Av.run(command)
36
- case result
37
- when /true/
38
- return true
39
- when /false/
40
- return false
41
- end
42
- end
43
28
  end
@@ -2,23 +2,32 @@ module Av
2
2
  class Cli
3
3
  attr_accessor :command
4
4
 
5
- def initialize
5
+ def initialize(options)
6
6
  found = []
7
- found << 'ffmpeg' if ::Av.detect_command('ffmpeg')
8
- found << 'avconv' if ::Av.detect_command('avprobe')
9
- ::Av.log("Found: #{found.inspect}")
7
+ found << 'ffmpeg' if self.detect_command('ffmpeg')
8
+ found << 'avconv' if self.detect_command('avprobe')
10
9
  if found.empty?
11
10
  raise Av::UnableToDetect, "Unable to detect any supported library"
12
11
  else
13
- found.each do |library|
14
- @command = Object.const_get('Av').const_get('Commands').const_get(library.capitalize).new
15
- end
12
+ @command = Object.const_get('Av').const_get('Commands').const_get(found.first.capitalize).new(options)
16
13
  end
14
+ ::Av.log("Found #{found.inspect}, using: #{found.first.capitalize}")
17
15
  end
18
-
16
+
19
17
  protected
20
18
  def method_missing name, *args, &block
21
19
  @command.send(name, *args, &block)
22
20
  end
21
+
22
+ def detect_command(command)
23
+ command = "if command -v #{command} 2>/dev/null; then echo \"true\"; else echo \"false\"; fi"
24
+ result = ::Av.run(command)
25
+ case result
26
+ when /true/
27
+ return true
28
+ when /false/
29
+ return false
30
+ end
31
+ end
23
32
  end
24
33
  end
@@ -4,21 +4,34 @@ module Av
4
4
  module Commands
5
5
  class Avconv < Base
6
6
 
7
- def initialize
8
- super
9
- @command_name = "avconv"
10
- @default_params = %Q(-loglevel "quiet") if Av.quiet
7
+ def initialize(options = {})
8
+ super(options)
9
+ @command_name = 'avconv'
10
+ @default_params['loglevel'] = 'quiet' unless options[:quite] == false
11
11
  end
12
12
 
13
13
  def filter_concat list
14
- @input_params << %Q(-i concat:#{list.join('\|')} -c copy)
14
+ add_input_param i: "concat:#{list.join('\|')} -c copy"
15
15
  self
16
16
  end
17
17
 
18
18
  def filter_volume vol
19
- @input_params << "-af volume=volume=#{vol}"
19
+ add_input_param af: "volume=volume=#{vol}"
20
20
  self
21
21
  end
22
+
23
+ def filter_rotate degrees
24
+ raise ::Av::InvalidFilterParameter unless degrees % 90 == 0
25
+ case degrees
26
+ when 90
27
+ add_input_param vf: 'clock'
28
+ when 180
29
+ add_input_param vf: 'vflip,hflip'
30
+ when 270
31
+ add_input_param vf: 'cclock'
32
+ end
33
+ end
34
+
22
35
  end
23
36
  end
24
37
  end
@@ -4,18 +4,22 @@ module Av
4
4
  module Commands
5
5
  # Common features across commands
6
6
  class Base
7
+ attr_accessor :options
7
8
  attr_accessor :command_name
8
9
  attr_accessor :input_params
9
10
  attr_accessor :output_params
11
+ attr_accessor :audio_filters
12
+ attr_accessor :video_filters
10
13
  attr_accessor :default_params
11
14
 
12
15
  attr_accessor :source
13
16
  attr_accessor :destination
14
17
 
15
- def initialize
18
+ def initialize(options = {})
16
19
  reset_input_filters
17
20
  reset_output_filters
18
21
  reset_default_filters
22
+ @options = options
19
23
  end
20
24
 
21
25
  def add_source src
@@ -27,60 +31,65 @@ module Av
27
31
  end
28
32
 
29
33
  def reset_input_filters
30
- @input_params = []
34
+ @input_params = ParamHash.new
35
+ @audio_filters = ParamHash.new
36
+ @video_filters = ParamHash.new
31
37
  end
32
38
 
33
39
  def reset_output_filters
34
- @output_params = []
40
+ @output_params = ParamHash.new
35
41
  end
36
42
 
37
43
  def reset_default_filters
38
- @output_params = []
44
+ @default_params = ParamHash.new
39
45
  end
40
46
 
41
- def add_input_filters hash
42
- hash.each do |k,v|
43
- @input_params << "-#{k} #{v}"
44
- end
47
+ def add_input_param *param
48
+ p = parse_param(param)
49
+ ::Av.log "Adding input parameter #{p}"
50
+ @input_params[p[0]] = [] unless @input_params.has_key?(p[0])
51
+ @input_params[p[0]] << p[1]
45
52
  self
46
53
  end
47
54
 
48
- def add_output_filters hash
49
- hash.each do |k,v|
50
- @output_params << "-#{k} #{v}"
51
- end
55
+ def set_input_params hash
56
+ @input_params = hash
57
+ end
58
+
59
+ def add_output_param *param
60
+ p = parse_param(param)
61
+ ::Av.log "Adding output parameter #{p}"
62
+ @output_params[p[0]] = [] unless @output_params.has_key?(p[0])
63
+ @output_params[p[0]] << p[1]
52
64
  self
53
65
  end
54
66
 
55
- def command_line
67
+ def set_output_params hash
68
+ @output_params = hash
69
+ end
70
+
71
+ def run
56
72
  raise Av::CommandError if (@source.nil? && @destination.nil?) || @command_name.nil?
57
73
 
58
74
  parameters = []
59
75
  parameters << @command_name
60
76
  parameters << @default_params if @default_params
61
77
  if @input_params
62
- parameters << @input_params.join(' ')
78
+ parameters << @input_params.to_s
63
79
  end
64
80
  parameters << %Q(-i "#{@source}") if @source
65
81
  if @output_params
66
- parameters << @output_params.join(' ')
82
+ parameters << @output_params.to_s
67
83
  end
68
84
  parameters << %Q(-y "#{@destination}") if @destination
69
- parameters.flatten.compact.join(" ").strip.squeeze(" ")
70
- end
71
-
72
- def run
73
- Av.run(command_line)
85
+ command_line = parameters.flatten.compact.join(" ").strip.squeeze(" ")
86
+ ::Av.run(command_line)
74
87
  end
75
88
 
76
89
  def identify path
77
90
  meta = {}
78
91
  command = %Q(#{@command_name} -i "#{File.expand_path(path)}" 2>&1)
79
- out = Av.run(command, [0,1])
80
- # rescue Av::CommandError
81
- # # Do nothing, we know ffmpeg/avconv will complain with:
82
- # # "At least one output file must be specified"
83
- # end
92
+ out = ::Av.run(command, [0,1])
84
93
  out.split("\n").each do |line|
85
94
  if line =~ /(([\d\.]*)\s.?)fps,/
86
95
  meta[:fps] = $1.to_i
@@ -103,6 +112,45 @@ module Av
103
112
  end
104
113
  meta
105
114
  end
115
+
116
+ def output_format format
117
+ case format
118
+ when 'jpg', 'jpeg', 'png', 'gif' # Images
119
+ add_output_param 'f', 'image2'
120
+ add_output_param 'vframes', '1'
121
+ when 'webm' # WebM
122
+ add_output_param 'f', 'webm'
123
+ add_output_param 'acodec', 'libvorbis'
124
+ add_output_param 'vcodec', 'libvpx'
125
+ when 'ogv' # Ogg Theora
126
+ add_output_param 'f', 'ogg'
127
+ add_output_param 'acodec', 'libvorbis'
128
+ add_output_param 'vcodec', 'libtheora'
129
+ when 'mp4'
130
+ add_output_param 'acodec', 'aac'
131
+ add_output_param 'strict', 'experimental'
132
+ end
133
+ end
134
+
135
+ # Children should override the following methods
136
+ def filter_rotate degrees
137
+ raise ::Av::FilterNotImplemented, 'rotate'
138
+ end
139
+
140
+ def parse_param param
141
+ list = []
142
+ if param.count == 2
143
+ list = param
144
+ elsif param.count == 1
145
+ case param[0].class.to_s
146
+ when 'Hash'
147
+ list[0], list[1] = param[0].to_a.flatten!
148
+ when 'Array'
149
+ list = param[0]
150
+ end
151
+ end
152
+ list
153
+ end
106
154
  end
107
155
  end
108
156
  end
@@ -5,9 +5,10 @@ module Av
5
5
  module Commands
6
6
  class Ffmpeg < Base
7
7
 
8
- def initialize
9
- super
8
+ def initialize(options = {})
9
+ super(options)
10
10
  @command_name = "ffmpeg"
11
+ # TODO handle quite for ffmpeg
11
12
  end
12
13
 
13
14
  def filter_concat list
@@ -17,12 +18,25 @@ module Av
17
18
  file.write("file '#{item}'\n")
18
19
  end
19
20
  end
20
- @input_params << "concat -i #{index_file.path}"
21
+ add_input_param concat: "-i #{index_file.path}"
21
22
  self
22
23
  end
23
24
 
24
25
  def filter_volume vol
25
- @input_params << "-af volume=#{vol}"
26
+ add_input_param af: "volume=#{vol}"
27
+ self
28
+ end
29
+
30
+ def filter_rotate degrees
31
+ raise ::Av::InvalidFilterParameter unless degrees % 90 == 0
32
+ case degrees
33
+ when 90
34
+ add_input_param vf: 'transpose=1'
35
+ when 180
36
+ add_input_param vf: 'vflip,hflip'
37
+ when 270
38
+ add_input_param vf: 'transpose=2'
39
+ end
26
40
  self
27
41
  end
28
42
  end
@@ -3,4 +3,6 @@ module Av
3
3
  class CommandError < Exception; end
4
4
  class InvalidInputFile < Exception; end
5
5
  class InvalidOutputFile < Exception; end
6
+ class InvalidFilterParameter < Exception; end
7
+ class FilterNotImplemented < Exception; end
6
8
  end
@@ -0,0 +1,12 @@
1
+ module Av
2
+ class ParamHash < Hash
3
+ def to_s
4
+ line = []
5
+ self.each do |option, value|
6
+ value = value.join(' ') unless value.is_a?(String)
7
+ line << "-#{option} #{value}"
8
+ end
9
+ line.join(' ')
10
+ end
11
+ end
12
+ end
@@ -1,3 +1,3 @@
1
1
  module Av
2
- VERSION = "0.0.6"
2
+ VERSION = "0.1.1"
3
3
  end
@@ -9,7 +9,7 @@ describe Av::Commands::Avconv do
9
9
  subject.filter_concat(list)
10
10
  end
11
11
 
12
- it { expect(subject.input_params.first).to include %Q(concat:one\\|two) }
12
+ it { expect(subject.input_params.to_s).to include %Q(concat:one\\|two) }
13
13
  end
14
14
 
15
15
  describe '.filter_volume' do
@@ -17,7 +17,7 @@ describe Av::Commands::Avconv do
17
17
  subject.filter_volume('0.5')
18
18
  end
19
19
 
20
- it { expect(subject.input_params.first).to eq "-af volume=volume=0.5" }
20
+ it { expect(subject.input_params.to_s).to eq "-af volume=volume=0.5" }
21
21
  end
22
22
  end
23
23
 
@@ -10,5 +10,45 @@ describe Av::Commands::Base do
10
10
  it { expect(meta).to be_a Hash }
11
11
  it { expect(meta.keys).to include :size, :fps, :length, :aspect }
12
12
  end
13
+
14
+ describe '.add_input_param' do
15
+ before do
16
+ subject.add_input_param({k: 'value'})
17
+ end
18
+ it { expect(subject.input_params.to_s).to eq '-k value' }
19
+ context 'multiple calls' do
20
+ before do
21
+ subject.add_input_param({k: 'value1'})
22
+ subject.add_input_param(:k, 'value2')
23
+ subject.add_input_param([:x, 'y'])
24
+ end
25
+ it { expect(subject.input_params.to_s).to eq '-k value value1 value2 -x y' }
26
+ end
27
+ end
28
+
29
+ describe '.add_output_param' do
30
+ before do
31
+ subject.add_output_param({k: 'value'})
32
+ end
33
+ it { expect(subject.output_params.to_s).to eq '-k value' }
34
+ context 'multiple calls' do
35
+ before do
36
+ subject.add_output_param({k: 'value1'})
37
+ subject.add_output_param(:k, 'value2')
38
+ subject.add_output_param([:x, 'y'])
39
+ end
40
+ it { expect(subject.output_params.to_s).to eq '-k value value1 value2 -x y' }
41
+ end
42
+ end
43
+
44
+ describe '.run' do
45
+ before do
46
+ subject.add_output_param(ar: 44100)
47
+ subject.add_source(source)
48
+ subject.add_destination(Tempfile.new(['one', '.ogv']).path)
49
+ end
50
+ it { expect { subject.run }.not_to raise_exception }
51
+
52
+ end
13
53
  end
14
54
 
@@ -9,7 +9,7 @@ describe Av::Commands::Ffmpeg do
9
9
  subject.filter_concat(list)
10
10
  end
11
11
 
12
- it { expect(subject.input_params.first).to include %Q(concat -i) }
12
+ it { expect(subject.input_params.to_s).to include %Q(concat -i) }
13
13
  end
14
14
 
15
15
  describe '.filter_volume' do
@@ -17,6 +17,6 @@ describe Av::Commands::Ffmpeg do
17
17
  subject.filter_volume('0.5')
18
18
  end
19
19
 
20
- it { expect(subject.input_params.first).to eq "-af volume=0.5" }
20
+ it { expect(subject.input_params.to_s).to eq "-af volume=0.5" }
21
21
  end
22
22
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: av
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Omar Abdel-Wahab
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-09-08 00:00:00.000000000 Z
11
+ date: 2014-09-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -86,6 +86,7 @@ files:
86
86
  - lib/av/commands/base.rb
87
87
  - lib/av/commands/ffmpeg.rb
88
88
  - lib/av/exceptions.rb
89
+ - lib/av/param_hash.rb
89
90
  - lib/av/version.rb
90
91
  - spec/av/av_spec.rb
91
92
  - spec/av/avconv_spec.rb