puremotion 0.0.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.
- data/.document +5 -0
- data/.gitignore +21 -0
- data/LICENSE +20 -0
- data/README.rdoc +18 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/lib/puremotion/codecs.rb +59 -0
- data/lib/puremotion/events/event.rb +69 -0
- data/lib/puremotion/events/generator.rb +50 -0
- data/lib/puremotion/media/stream/audio.rb +0 -0
- data/lib/puremotion/media/stream/base.rb +7 -0
- data/lib/puremotion/media/stream/collection.rb +5 -0
- data/lib/puremotion/media/stream/video.rb +61 -0
- data/lib/puremotion/media/stream.rb +4 -0
- data/lib/puremotion/media.rb +490 -0
- data/lib/puremotion/recipes/ipod.yml +12 -0
- data/lib/puremotion/thread.rb +153 -0
- data/lib/puremotion/tools/ffmpeg.rb +141 -0
- data/lib/puremotion/transcode/recipe.rb +250 -0
- data/lib/puremotion/transcode/transcode.rb +153 -0
- data/lib/puremotion.rb +22 -0
- data/puremotion.gemspec +68 -0
- data/test/helper.rb +10 -0
- data/test/test_puremotion.rb +7 -0
- metadata +89 -0
@@ -0,0 +1,141 @@
|
|
1
|
+
module PureMotion::Tools
|
2
|
+
|
3
|
+
class FFmpeg
|
4
|
+
|
5
|
+
class Status
|
6
|
+
|
7
|
+
NOT_STARTED = 1
|
8
|
+
INITIALIZING = 2
|
9
|
+
ANALYZING = 4
|
10
|
+
PREPARING_OUTPUT = 8
|
11
|
+
ENCODING = 16
|
12
|
+
ERROR = 32
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_reader :args
|
17
|
+
attr_accessor :output
|
18
|
+
|
19
|
+
event :line
|
20
|
+
event :complete
|
21
|
+
event :exited
|
22
|
+
event :status_change
|
23
|
+
|
24
|
+
@status = Status::NOT_STARTED
|
25
|
+
|
26
|
+
def self.run(args = {})
|
27
|
+
FFmpeg.new( args )
|
28
|
+
end
|
29
|
+
|
30
|
+
def initialize(params = {})
|
31
|
+
if params.class != Hash then raise ArgumentError, "Invalid parameters" end
|
32
|
+
|
33
|
+
@defaults = {
|
34
|
+
:ffmpeg => 'ffmpeg',
|
35
|
+
:options => nil
|
36
|
+
}
|
37
|
+
|
38
|
+
@params = params
|
39
|
+
|
40
|
+
@options = @params[:options]
|
41
|
+
|
42
|
+
if @options.nil? then
|
43
|
+
raise ArgumentError, "No options given"
|
44
|
+
end
|
45
|
+
|
46
|
+
@output = []
|
47
|
+
|
48
|
+
go
|
49
|
+
end
|
50
|
+
|
51
|
+
def go
|
52
|
+
|
53
|
+
@pio = IO.popen("ffmpeg #{@options} 2>&1")
|
54
|
+
|
55
|
+
temp = ''
|
56
|
+
|
57
|
+
PureMotion::Thread.new do
|
58
|
+
@pio.each_byte do |l|
|
59
|
+
if l == 10 or l == 13 then
|
60
|
+
@output.push temp
|
61
|
+
line(temp)
|
62
|
+
temp = ''
|
63
|
+
l = ''
|
64
|
+
else
|
65
|
+
l = l.chr
|
66
|
+
end
|
67
|
+
temp = temp + l
|
68
|
+
#@output << l.gsub("\r","\n")
|
69
|
+
end
|
70
|
+
if @pio.eof? then
|
71
|
+
@done = true
|
72
|
+
complete(true)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
def ran?
|
79
|
+
@pio.eof? unless @pio.nil?
|
80
|
+
false
|
81
|
+
#!find(/^FFmpeg/).nil?
|
82
|
+
end
|
83
|
+
|
84
|
+
def ended?
|
85
|
+
return false unless ran?
|
86
|
+
@pio.eof?
|
87
|
+
end
|
88
|
+
|
89
|
+
def version
|
90
|
+
return nil unless ran?
|
91
|
+
find(/^FFmpeg version (\S+)/)
|
92
|
+
end
|
93
|
+
|
94
|
+
def find(regexp)
|
95
|
+
m = regexp.match(@output)
|
96
|
+
return m[1] if m
|
97
|
+
nil
|
98
|
+
end
|
99
|
+
|
100
|
+
def status
|
101
|
+
@status
|
102
|
+
end
|
103
|
+
|
104
|
+
private
|
105
|
+
|
106
|
+
def prepare_args
|
107
|
+
@args = []
|
108
|
+
@args << ['i', @input]
|
109
|
+
|
110
|
+
args = []
|
111
|
+
|
112
|
+
strings = []
|
113
|
+
|
114
|
+
@args.each do |arg, value|
|
115
|
+
if value.nil? then value = '' end
|
116
|
+
value = '"' + value.to_s + '"' unless value.index(' ').nil?
|
117
|
+
|
118
|
+
args << [ arg, value]
|
119
|
+
|
120
|
+
if value.empty? or value =~ /^\s*$/ then
|
121
|
+
value = ''
|
122
|
+
else
|
123
|
+
value = ' ' << value
|
124
|
+
end
|
125
|
+
|
126
|
+
strings << ( '-' << arg << value )
|
127
|
+
end
|
128
|
+
|
129
|
+
if !@output.nil? then strings << '"' + @output + '"' end
|
130
|
+
|
131
|
+
@args = strings.join(' ')
|
132
|
+
end
|
133
|
+
|
134
|
+
def status=(status_const)
|
135
|
+
@status = status_const
|
136
|
+
status_change(status_const)
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
@@ -0,0 +1,250 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module PureMotion::Transcode
|
4
|
+
|
5
|
+
class Recipe
|
6
|
+
|
7
|
+
def self.from_file(file)
|
8
|
+
|
9
|
+
file.sub!(/\.yml/, '') if file =~ /\.yml/
|
10
|
+
|
11
|
+
built_in_path = File.join( File.expand_path(File.dirname(__FILE__)), '../recipes', file + '.yml')
|
12
|
+
|
13
|
+
where = nil
|
14
|
+
path = nil
|
15
|
+
|
16
|
+
if File.exists? built_in_path then where = :internal end
|
17
|
+
if File.exists? file then where = :external end
|
18
|
+
|
19
|
+
raise(ArgumentError, "Recipe file '#{file}' not found") if where.nil?
|
20
|
+
|
21
|
+
case where
|
22
|
+
when :internal
|
23
|
+
path = built_in_path
|
24
|
+
when :external
|
25
|
+
path = file
|
26
|
+
end
|
27
|
+
|
28
|
+
return self.new({ :source => :file, :recipe => path })
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.from_name(name)
|
32
|
+
|
33
|
+
n = name.to_s
|
34
|
+
|
35
|
+
raise(ArgumentError, 'Invalid recipe name') if not n.is_a?(String)
|
36
|
+
|
37
|
+
return from_file(n)
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.build(hash)
|
42
|
+
return self.new({ :source => :hash, :recipe => hash})
|
43
|
+
end
|
44
|
+
|
45
|
+
@recipe = {
|
46
|
+
'format' => :skip
|
47
|
+
}
|
48
|
+
@video = {}
|
49
|
+
@audio = {}
|
50
|
+
@container = nil
|
51
|
+
|
52
|
+
attr_accessor :audio, :video, :arg_string, :args
|
53
|
+
|
54
|
+
def initialize(opts)
|
55
|
+
|
56
|
+
if not opts.is_a? Hash then raise(ArgumentError, "opts should be a hash") end
|
57
|
+
|
58
|
+
defaults = {
|
59
|
+
:source => :hash,
|
60
|
+
:recipe => nil
|
61
|
+
}
|
62
|
+
|
63
|
+
@opts = defaults.merge!(opts)
|
64
|
+
|
65
|
+
@recipe = @opts[:recipe]
|
66
|
+
|
67
|
+
if @recipe.nil? then raise(ArgumentError, "No recipe given") end
|
68
|
+
|
69
|
+
case @opts[:source]
|
70
|
+
when :hash
|
71
|
+
hash_build
|
72
|
+
when :file
|
73
|
+
file_build @recipe
|
74
|
+
when :name
|
75
|
+
from_name @recipe
|
76
|
+
else
|
77
|
+
raise(ArgumentError, 'Invalid recipe source')
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
def parse o
|
83
|
+
|
84
|
+
recipe = nil
|
85
|
+
|
86
|
+
recipe = o['recipe'] if o.has_key? 'recipe'
|
87
|
+
recipe = o if o.has_key? 'video' or o.has_key? 'audio'
|
88
|
+
|
89
|
+
raise ArgumentError, 'Bad recipe' if recipe.nil?
|
90
|
+
|
91
|
+
video = recipe['video']
|
92
|
+
audio = recipe['audio']
|
93
|
+
|
94
|
+
parse_video = lambda do |source_video|
|
95
|
+
|
96
|
+
@video = {}
|
97
|
+
@video.merge! source_video
|
98
|
+
|
99
|
+
# Video codec
|
100
|
+
|
101
|
+
# End video codec
|
102
|
+
|
103
|
+
# Video bitrate
|
104
|
+
if @video['bitrate'].nil? then @video['bitrate'] = :skip else
|
105
|
+
begin
|
106
|
+
@video['bitrate'] = @video['bitrate'].to_i if not @video['bitrate'].is_a? Integer
|
107
|
+
rescue
|
108
|
+
raise ArgumentError, 'Video bitrate must be a number'
|
109
|
+
end
|
110
|
+
|
111
|
+
@video['bitrate'] *= 1024
|
112
|
+
raise ArgumentError, 'Recipe: video bitrate too low' if @video['bitrate'] < 1024
|
113
|
+
end
|
114
|
+
# End video
|
115
|
+
|
116
|
+
# Video resolution
|
117
|
+
if @video['resolution'].nil? then @video['resolution'] = :skip else
|
118
|
+
if not @video['resolution'] =~ /\d*x\d*/ then
|
119
|
+
raise ArgumentError, "Invalid resolution"
|
120
|
+
end
|
121
|
+
end
|
122
|
+
# End video resolution
|
123
|
+
|
124
|
+
|
125
|
+
|
126
|
+
end
|
127
|
+
|
128
|
+
parse_audio = lambda do |source_audio|
|
129
|
+
|
130
|
+
@audio = {
|
131
|
+
'codec' => nil,
|
132
|
+
'bitrate' => nil,
|
133
|
+
}
|
134
|
+
|
135
|
+
@audio.merge! source_audio
|
136
|
+
|
137
|
+
# Audio codec
|
138
|
+
if @audio['codec'].nil? then @audio['codec'] = :skip else
|
139
|
+
raise ArgumentError, 'Recipe: Invalid Audio Codec' unless PureMotion::Codecs.valid? @audio['codec'], :audio
|
140
|
+
@audio['codec'] = PureMotion::Codecs.find(@audio['codec']).ffmpeg_name
|
141
|
+
end
|
142
|
+
# End Audio codec
|
143
|
+
|
144
|
+
# Audio bitrate
|
145
|
+
if @audio['bitrate'].nil? then @audio['bitrate'] = :skip else
|
146
|
+
begin
|
147
|
+
@audio['bitrate'] = @audio['bitrate'].to_i if not @audio['bitrate'].is_a? Integer
|
148
|
+
rescue
|
149
|
+
raise ArgumentError, 'Audio bitrate must be a number'
|
150
|
+
end
|
151
|
+
|
152
|
+
@audio['bitrate'] *= 1024
|
153
|
+
raise ArgumentError, 'Recipe: Audio bitrate too low' if @audio['bitrate'] < 1024
|
154
|
+
end
|
155
|
+
# End Audio Bitrate
|
156
|
+
|
157
|
+
# Audio channels
|
158
|
+
if @audio['channels'].nil? then @audio['channels'] = :skip else
|
159
|
+
channel_types = { 'mono' => 1, 'stereo' => 2 }
|
160
|
+
if @audio['channels'].is_a? String then
|
161
|
+
@audio['channels'].downcase!
|
162
|
+
if channel_types[@audio['channels']].nil? then
|
163
|
+
@audio['channels'] = :skip
|
164
|
+
else
|
165
|
+
@audio['channels'] = channel_types[@audio['channels']]
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
# End audio channels
|
170
|
+
|
171
|
+
end
|
172
|
+
|
173
|
+
parse_video.call video unless video.nil?
|
174
|
+
parse_audio.call audio unless audio.nil?
|
175
|
+
|
176
|
+
@recipe = {}
|
177
|
+
|
178
|
+
if recipe['format'].nil? then recipe['format'] = :skip else
|
179
|
+
@recipe.store('format', recipe['format'])
|
180
|
+
end
|
181
|
+
|
182
|
+
end
|
183
|
+
|
184
|
+
def valid?
|
185
|
+
valid = true
|
186
|
+
if audio? and !valid_audio? then valid = false end
|
187
|
+
if video? and !valid_video? then valid = false end
|
188
|
+
valid
|
189
|
+
end
|
190
|
+
|
191
|
+
def valid_video?
|
192
|
+
|
193
|
+
end
|
194
|
+
|
195
|
+
def valid_audio?
|
196
|
+
|
197
|
+
end
|
198
|
+
|
199
|
+
def to_args
|
200
|
+
|
201
|
+
args = []
|
202
|
+
arg_strings = []
|
203
|
+
|
204
|
+
args[0] = ['f', @recipe['format'] ]
|
205
|
+
args[1] = ['acodec', @audio['codec'] ]
|
206
|
+
args[2] = ['vcodec', @video['codec'] ]
|
207
|
+
args[3] = ['vb', @video['bitrate'] ]
|
208
|
+
args[4] = ['s', @video['resolution']]
|
209
|
+
args[5] = ['r', @video['fps'] ]
|
210
|
+
args[6] = ['ab', @audio['bitrate'] ]
|
211
|
+
args[7] = ['ac', @audio['channels'] ]
|
212
|
+
|
213
|
+
required_value_args = ['f', 'vcodec', 'acodec', 'vb', 's', 'r', 'ab', 'ac']
|
214
|
+
|
215
|
+
args.each do |arg|
|
216
|
+
next if required_value_args.include? arg[0] and arg[1].nil?
|
217
|
+
arg_strings << format_arg(arg[0], arg[1])
|
218
|
+
end
|
219
|
+
|
220
|
+
@args = arg_strings.join(' ')
|
221
|
+
|
222
|
+
@args
|
223
|
+
|
224
|
+
end
|
225
|
+
|
226
|
+
private
|
227
|
+
|
228
|
+
def format_arg name, value
|
229
|
+
name = '' if name.nil?
|
230
|
+
value = '' if value.nil?
|
231
|
+
value = value.to_s
|
232
|
+
value.gsub! '"', ''
|
233
|
+
value = '"' + value + '"' if value =~ /\s/
|
234
|
+
return value if name == :non
|
235
|
+
return name if value == :non
|
236
|
+
'-' + name.to_s + ' ' + value.to_s
|
237
|
+
end
|
238
|
+
|
239
|
+
def hash_build
|
240
|
+
|
241
|
+
end
|
242
|
+
|
243
|
+
def file_build(file)
|
244
|
+
@yaml = ::YAML.load( File.read(file) )
|
245
|
+
parse @yaml
|
246
|
+
end
|
247
|
+
|
248
|
+
end
|
249
|
+
|
250
|
+
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
module PureMotion::Transcode
|
2
|
+
|
3
|
+
@@recipes = []
|
4
|
+
|
5
|
+
def self.do(media, params)
|
6
|
+
return Transcode.new(media, params)
|
7
|
+
end
|
8
|
+
|
9
|
+
class Transcode < Object
|
10
|
+
|
11
|
+
event :progress
|
12
|
+
event :complete
|
13
|
+
event :error
|
14
|
+
event :status_change
|
15
|
+
|
16
|
+
@status
|
17
|
+
@media = nil
|
18
|
+
|
19
|
+
@ffmpeg = nil
|
20
|
+
|
21
|
+
def initialize(media, params)
|
22
|
+
|
23
|
+
@status = Status::NOT_STARTED
|
24
|
+
|
25
|
+
@params = {
|
26
|
+
:output => nil,
|
27
|
+
:overwrite => false,
|
28
|
+
:recipe => nil
|
29
|
+
}
|
30
|
+
|
31
|
+
raise ArgumentError, "Invalid paramters given" unless params.is_a? Hash
|
32
|
+
|
33
|
+
@params.merge!(params)
|
34
|
+
|
35
|
+
raise ArgumentError, "No output file given" if @params[:output].nil?
|
36
|
+
|
37
|
+
case @params[:recipe]
|
38
|
+
when String
|
39
|
+
set_recipe Recipe.from_file(@params[:recipe])
|
40
|
+
when Hash
|
41
|
+
set_recipe Recipe.build(@params[:recipe])
|
42
|
+
when Recipe
|
43
|
+
set_recipe @params[:recipe]
|
44
|
+
when Symbol
|
45
|
+
set_recipe Recipe.from_name(@params[:recipe].to_s)
|
46
|
+
else
|
47
|
+
raise ArgumentError, "Invalid recipe"
|
48
|
+
end
|
49
|
+
|
50
|
+
@media = find_media(media)
|
51
|
+
|
52
|
+
if @media.analysed?
|
53
|
+
prepare
|
54
|
+
else
|
55
|
+
|
56
|
+
@media.analysed + lambda do |media, raw|
|
57
|
+
prepare
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
raise ArgumentError, "Output file #{@params[:output]} exists and overwrite disabled" if File.exists?(@params[:output]) and !@params[:overwrite]
|
63
|
+
|
64
|
+
@ffmpeg = PureMotion::Tools::FFmpeg.run :options => "-i #{@media.file} #{'-y' if @params[:overwrite]} " + @recipe.to_args + " \"#{@params[:output]}\""
|
65
|
+
|
66
|
+
@ffmpeg.line + lambda do |ffmpeg, line|
|
67
|
+
handle_output line
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
def run
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
def cancel
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
def cancel!
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
def set_recipe(recipe)
|
87
|
+
@params[:recipe] = recipe
|
88
|
+
@recipe = recipe
|
89
|
+
end
|
90
|
+
|
91
|
+
def set_status(status)
|
92
|
+
@status = status
|
93
|
+
status_change(@status)
|
94
|
+
end
|
95
|
+
|
96
|
+
def find_media(media)
|
97
|
+
|
98
|
+
case media
|
99
|
+
when String
|
100
|
+
return PureMotion::Media.new(media)
|
101
|
+
when PureMotion::Media
|
102
|
+
return media
|
103
|
+
else
|
104
|
+
raise Error, "Invalid media given"
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
|
109
|
+
def handle_output line
|
110
|
+
puts line
|
111
|
+
# /^frame=\s*(?<frame>\d*)\s*fps=\s*(?<fps>\d*)\s*q=(?<q>\S*)\s*size=\s*(?<size>[\d]*)(?<size_unit>[kmg]B)\s*time=\s*(?<time>[\d.]*)\s*bitrate=\s*(?<bitrate>[\d.]*)(?<bitrate_unit>[km]b).*$/
|
112
|
+
progress_line = /frame=\s*(\d*)\s*fps=\s*(\d*)\s*q=(\S*)\s*[L]?size=\s*([\d]*)([kmg]B)\s*time=\s*([\d.]*)\s*bitrate=\s*([\d.]*)([km]b)/
|
113
|
+
# 1 => frame
|
114
|
+
# 2 => fps
|
115
|
+
# 3 => q
|
116
|
+
# 4 => size
|
117
|
+
# 5 => size_unit
|
118
|
+
# 6 => time
|
119
|
+
# 7 => bitrate
|
120
|
+
# 8 => bitrate_unit
|
121
|
+
handle_progress(progress_line.match(line)) if progress_line.match(line)
|
122
|
+
end
|
123
|
+
|
124
|
+
def handle_progress line
|
125
|
+
p = {
|
126
|
+
:frame => line[1].to_i,
|
127
|
+
:fps => line[2].to_i,
|
128
|
+
:q => line[3].to_f,
|
129
|
+
:size => line[4].to_i,
|
130
|
+
:time => line[6].to_f,
|
131
|
+
:bitrate => line[7].to_f,
|
132
|
+
:precent => ((100.00 / @media.detail(:duration, :seconds)) * line[6].to_f).to_i
|
133
|
+
}
|
134
|
+
p[:percent] = 100 if p[:percent] > 100
|
135
|
+
progress(p)
|
136
|
+
end
|
137
|
+
|
138
|
+
# Fire progress event
|
139
|
+
# complete(p)
|
140
|
+
end
|
141
|
+
|
142
|
+
class Error < Exception
|
143
|
+
|
144
|
+
|
145
|
+
end
|
146
|
+
|
147
|
+
class Status
|
148
|
+
|
149
|
+
NOT_STARTED = -1
|
150
|
+
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
data/lib/puremotion.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
req = File.expand_path(File.dirname(__FILE__)) + '/'
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
|
5
|
+
module PureMotion
|
6
|
+
|
7
|
+
end
|
8
|
+
|
9
|
+
require req + 'puremotion/events/event'
|
10
|
+
require req + 'puremotion/events/generator'
|
11
|
+
|
12
|
+
Object.extend(PureMotion::Events::Generator)
|
13
|
+
|
14
|
+
require req + 'puremotion/thread'
|
15
|
+
require req + 'puremotion/media'
|
16
|
+
require req + 'puremotion/media/stream'
|
17
|
+
require req + 'puremotion/media/stream/base'
|
18
|
+
require req + 'puremotion/media/stream/video'
|
19
|
+
require req + 'puremotion/codecs'
|
20
|
+
require req + 'puremotion/transcode/transcode'
|
21
|
+
require req + 'puremotion/transcode/recipe'
|
22
|
+
require req + 'puremotion/tools/ffmpeg'
|
data/puremotion.gemspec
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{puremotion}
|
8
|
+
s.version = "0.0.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Ominiom"]
|
12
|
+
s.date = %q{2009-11-14}
|
13
|
+
s.description = %q{A Ruby wrapper for analysis and conversion of media using FFmpeg}
|
14
|
+
s.email = %q{iain.iw.wilson@googlemail.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".gitignore",
|
22
|
+
"LICENSE",
|
23
|
+
"README.rdoc",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"lib/puremotion.rb",
|
27
|
+
"lib/puremotion/codecs.rb",
|
28
|
+
"lib/puremotion/events/event.rb",
|
29
|
+
"lib/puremotion/events/generator.rb",
|
30
|
+
"lib/puremotion/media.rb",
|
31
|
+
"lib/puremotion/media/stream.rb",
|
32
|
+
"lib/puremotion/media/stream/audio.rb",
|
33
|
+
"lib/puremotion/media/stream/base.rb",
|
34
|
+
"lib/puremotion/media/stream/collection.rb",
|
35
|
+
"lib/puremotion/media/stream/video.rb",
|
36
|
+
"lib/puremotion/recipes/ipod.yml",
|
37
|
+
"lib/puremotion/thread.rb",
|
38
|
+
"lib/puremotion/tools/ffmpeg.rb",
|
39
|
+
"lib/puremotion/transcode/recipe.rb",
|
40
|
+
"lib/puremotion/transcode/transcode.rb",
|
41
|
+
"puremotion.gemspec",
|
42
|
+
"test/helper.rb",
|
43
|
+
"test/test_puremotion.rb"
|
44
|
+
]
|
45
|
+
s.homepage = %q{http://github.com/ominiom/puremotion}
|
46
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
47
|
+
s.require_paths = ["lib"]
|
48
|
+
s.rubygems_version = %q{1.3.5}
|
49
|
+
s.summary = %q{PureMotion}
|
50
|
+
s.test_files = [
|
51
|
+
"test/helper.rb",
|
52
|
+
"test/test_puremotion.rb"
|
53
|
+
]
|
54
|
+
|
55
|
+
if s.respond_to? :specification_version then
|
56
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
57
|
+
s.specification_version = 3
|
58
|
+
|
59
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
60
|
+
s.add_development_dependency(%q<thoughtbot-shoulda>, [">= 0"])
|
61
|
+
else
|
62
|
+
s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
|
63
|
+
end
|
64
|
+
else
|
65
|
+
s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
data/test/helper.rb
ADDED