av 0.0.6 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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