flvtool2 1.0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,297 @@
1
+ # Copyright (c) 2005 Norman Timmler (inlet media e.K., Hamburg, Germany)
2
+ # All rights reserved.
3
+ #
4
+ # Redistribution and use in source and binary forms, with or without
5
+ # modification, are permitted provided that the following conditions
6
+ # are met:
7
+ # 1. Redistributions of source code must retain the above copyright
8
+ # notice, this list of conditions and the following disclaimer.
9
+ # 2. Redistributions in binary form must reproduce the above copyright
10
+ # notice, this list of conditions and the following disclaimer in the
11
+ # documentation and/or other materials provided with the distribution.
12
+ # 3. The name of the author may not be used to endorse or promote products
13
+ # derived from this software without specific prior written permission.
14
+ #
15
+ # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16
+ # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17
+ # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18
+ # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19
+ # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20
+ # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21
+ # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22
+ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23
+ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24
+ # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
+
26
+
27
+ require 'flv'
28
+ require 'mixml'
29
+ require 'miyaml'
30
+
31
+ module FLVTool2
32
+
33
+ module Base
34
+
35
+ class << self
36
+
37
+ def execute!(options)
38
+
39
+ options[:commands].each do |command|
40
+ before_filter = "before_#{command.to_s}".intern
41
+ send(before_filter, options) if respond_to? before_filter
42
+ end
43
+
44
+ process_files(options) do |stream, in_path, out_path|
45
+ write_stream = false
46
+ options[:commands].each do |command|
47
+ write_stream = true if send( command, options, stream, in_path, out_path )
48
+ end
49
+ stream.write if write_stream && !options[:simulate]
50
+ end
51
+
52
+ options[:commands].each do |command|
53
+ after_filter = "after_#{command.to_s}".intern
54
+ send(after_filter, options) if respond_to? after_filter
55
+ end
56
+ end
57
+
58
+
59
+ def add(options, stream, in_path, out_path)
60
+ tag_structures = MiXML.parse( File.open( options[:tag_file], File::RDONLY ) { |file| file.readlines }.join )
61
+
62
+ add_tag = Proc.new do |data|
63
+
64
+ tag = FLV::FLVMetaTag.new
65
+
66
+ overwrite = ( data['overwrite'] && data['overwrite'].downcase ) == 'true' || false
67
+ data.delete( 'overwrite' )
68
+
69
+ tag.event = data['event'] || 'event'
70
+ data.delete( 'event' )
71
+
72
+ tag.timestamp = ( data['timestamp'] && data['timestamp'].to_i ) || 0
73
+ tag.timestamp = stream.find_nearest_keyframe_video_tag(tag.timestamp).timestamp if options[:keyframe_mode] && data['type'] == 'navigation'
74
+ data.delete( 'timestamp' )
75
+ data['time'] = tag.timestamp / 1000
76
+
77
+ tag.meta_data.merge!( data )
78
+
79
+ stream.add_tags( tag, false, overwrite )
80
+ end
81
+
82
+ tag_structures['tags'].each do |tag_name, value|
83
+ case tag_name
84
+ when 'metatag'
85
+ if value.class == Array
86
+ value.each { |_value| add_tag.call( _value ) }
87
+ else
88
+ add_tag.call( value )
89
+ end
90
+ else
91
+ end
92
+ end
93
+
94
+ return true
95
+ end
96
+
97
+
98
+ def debug(options, stream, in_path, out_path)
99
+
100
+ puts "---\n"
101
+ puts "path: #{in_path}"
102
+
103
+ unless stream.nil?
104
+ if options[:tag_number]
105
+ puts " tag_number: #{options[:tag_number]}"
106
+ puts " " + stream.tags[ options[:tag_number] - 1 ].inspect.join( "\n " )
107
+ else
108
+ stream.tags.each_with_index do |tag, index|
109
+ puts "##{index + 1} #{tag.info}"
110
+ end
111
+ end
112
+ end
113
+
114
+ return false
115
+ end
116
+
117
+
118
+ def cut(options, stream, in_path, out_path)
119
+
120
+ in_point = options[:keyframe_mode] ? stream.find_nearest_keyframe_video_tag(options[:in_point] || 0).timestamp : options[:in_point]
121
+ stream.cut( :in_point => in_point, :out_point => options[:out_point], :collapse => options[:collapse] )
122
+
123
+ return true
124
+ end
125
+
126
+
127
+ def update(options, stream, in_path, out_path)
128
+
129
+ if (
130
+ options[:preserve] &&
131
+ (
132
+ !stream.on_meta_data_tag ||
133
+ ( stream.on_meta_data_tag && stream.on_meta_data_tag.meta_data['metadatacreator'] != options[:metadatacreator] )
134
+ )
135
+ ) || !options[:preserve]
136
+
137
+ add_meta_data_tag( stream, options )
138
+
139
+ return true
140
+ else
141
+ puts 'Input file is FLV v1.1 yet. No update necessary.' if options[:verbose]
142
+
143
+ return false
144
+ end
145
+ end
146
+
147
+
148
+ def before_print(options)
149
+ puts "<?xml version=\"1.0\"?>\n<fileset>" if options[:xml]
150
+ end
151
+
152
+ def print(options, stream, in_path, out_path)
153
+
154
+ if options[:xml]
155
+ puts " <flv name=\"#{in_path}\">"
156
+ puts MiXML.dump( stream.on_meta_data_tag && stream.on_meta_data_tag.meta_data, 2 )
157
+ puts " </flv>"
158
+ else
159
+ puts MiYAML.dump( { in_path => ( stream.on_meta_data_tag && stream.on_meta_data_tag.meta_data ) } )
160
+ end
161
+
162
+ return false
163
+ end
164
+
165
+ def object_to_hash(object)
166
+ object.instance_variables.inject( {} ) do |hash, variable|
167
+ hash[variable.gsub('@', '')] = object.instance_variable_get( variable.intern )
168
+ hash
169
+ end
170
+ end
171
+
172
+ def after_print(options)
173
+ puts '</fileset>' if options[:xml]
174
+ end
175
+
176
+
177
+ def add_meta_data_tag(stream, options)
178
+ # add onLastSecond tag
179
+ onlastsecond = FLV::FLVMetaTag.new
180
+ onlastsecond.event = 'onLastSecond'
181
+ onlastsecond.timestamp = ((stream.duration - 1) * 1000).to_int
182
+ stream.add_tags(onlastsecond, false) if onlastsecond.timestamp >= 0
183
+
184
+ stream.add_meta_tag({ 'metadatacreator' => options[:metadatacreator], 'metadatadate' => Time.now }.merge(options[:metadata]))
185
+ unless options[:compatibility_mode]
186
+ stream.on_meta_data_tag.meta_data['duration'] += (stream.frame_sequence || 0) / 1000.0
187
+ end
188
+ end
189
+
190
+
191
+
192
+
193
+ def process_files(options)
194
+
195
+ if options[:in_pipe]
196
+
197
+ unless options[:omit_out] || options[:out_path].nil?
198
+ create_directories_for_path( options[:out_path] )
199
+ out_path = options[:out_path]
200
+ else
201
+ out_path = nil
202
+ end
203
+
204
+ begin
205
+ stream = open_stream( 'pipe', out_path )
206
+ yield stream, 'pipe', out_path
207
+ begin
208
+ stream.close
209
+ rescue
210
+ end
211
+
212
+ rescue Exception => e
213
+ show_exception(e, options)
214
+ end
215
+
216
+ else
217
+
218
+ if File.directory?( options[:in_path] )
219
+ pattern = options[:recursive] ? "#{File::SEPARATOR}**#{File::SEPARATOR}*.flv" : "#{File::SEPARATOR}*.flv"
220
+ file_names = Dir[options[:in_path] + pattern]
221
+ else
222
+ file_names = [options[:in_path]]
223
+ end
224
+
225
+ file_names.each do |in_path|
226
+
227
+ if options[:out_pipe]
228
+ out_path = 'pipe'
229
+ else
230
+ out_path = options[:out_path]
231
+ unless options[:out_path].nil?
232
+ out_path = in_path.gsub( options[:in_path], options[:out_path] )
233
+ create_directories_for_path( out_path )
234
+ end
235
+ end
236
+
237
+ begin
238
+ stream = open_stream( in_path, out_path, options[:stream_log] )
239
+ yield stream, in_path, out_path
240
+
241
+ begin
242
+ stream.close
243
+ rescue
244
+ end
245
+
246
+ rescue Exception => e
247
+ show_exception(e, options)
248
+ end
249
+ end
250
+ end
251
+ end
252
+
253
+ def open_stream(in_path, out_path = nil, stream_log = false)
254
+ attributes = (RUBY_PLATFORM =~ /win32/) ? File::BINARY : 0
255
+
256
+ if in_path == 'pipe'
257
+ in_stream = $stdin
258
+ elsif in_path == out_path || out_path.nil?
259
+ in_stream = File.open( in_path, File::RDWR|attributes )
260
+ else
261
+ in_stream = File.open( in_path, File::RDONLY|attributes )
262
+ end
263
+
264
+ if out_path == 'pipe' || ( in_path == 'pipe' && out_path.nil? )
265
+ out_stream = $stdout
266
+ elsif in_path != out_path && !out_path.nil?
267
+ out_stream = File.open( out_path, File::CREAT|File::WRONLY|attributes )
268
+ else
269
+ out_stream = nil
270
+ end
271
+
272
+ FLV::FLVStream.new( in_stream, out_stream, stream_log )
273
+ end
274
+
275
+ def create_directories_for_path(path_to_build)
276
+ parts = path_to_build.split(File::SEPARATOR)
277
+ parts.shift #removes '/' or 'c:\'
278
+ parts.pop # removes filename
279
+
280
+ parts.inject('') do |path, dir|
281
+ begin
282
+ path += File::SEPARATOR + dir
283
+ Dir.mkdir path
284
+ rescue Object => e
285
+ raise e unless File.directory?(path)
286
+ end
287
+ path
288
+ end
289
+ end
290
+
291
+ def show_exception(e, options)
292
+ puts "ERROR: #{e.message}\nERROR: #{e.backtrace.join("\nERROR: ")}"
293
+ puts "Skipping file #{options[:in_path]}\n" if options[:verbose]
294
+ end
295
+ end
296
+ end
297
+ end
@@ -0,0 +1,10 @@
1
+ module FLVTool2
2
+
3
+ PROGRAMM_VERSION = [1, 0, 6]
4
+ PROGRAMM_VERSION_EXTENSION = ''
5
+
6
+ def self.version
7
+ "#{PROGRAMM_VERSION.join('.')}#{PROGRAMM_VERSION_EXTENSION}"
8
+ end
9
+ end
10
+
@@ -0,0 +1,119 @@
1
+ # Copyright (c) 2005 Norman Timmler (inlet media e.K., Hamburg, Germany)
2
+ # All rights reserved.
3
+ #
4
+ # Redistribution and use in source and binary forms, with or without
5
+ # modification, are permitted provided that the following conditions
6
+ # are met:
7
+ # 1. Redistributions of source code must retain the above copyright
8
+ # notice, this list of conditions and the following disclaimer.
9
+ # 2. Redistributions in binary form must reproduce the above copyright
10
+ # notice, this list of conditions and the following disclaimer in the
11
+ # documentation and/or other materials provided with the distribution.
12
+ # 3. The name of the author may not be used to endorse or promote products
13
+ # derived from this software without specific prior written permission.
14
+ #
15
+ # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16
+ # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17
+ # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18
+ # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19
+ # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20
+ # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21
+ # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22
+ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23
+ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24
+ # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
+
26
+ class MiXML
27
+
28
+ def self.parse(xml)
29
+ current = {}
30
+ xml.scan( /<([!\?].*?)>|<([^\/].*?)>|<\/(.+?)>|([^<>]*)/m ) do |ignore, open_tag, close_tag, cdata|
31
+ if open_tag
32
+ tag_name = open_tag.match( /(\w+)\s?/ )[1]
33
+
34
+ parameters = {}
35
+ open_tag.scan( /(\w+)=\"(.*?)\"/ ) { |key, value| parameters[key] = value }
36
+
37
+ parameters[:parent] = current
38
+
39
+ if current[tag_name].class == Array
40
+ current[tag_name] << parameters
41
+ current = current[tag_name].last
42
+ else
43
+ if current[tag_name]
44
+ current[tag_name] = [ current[tag_name], parameters ]
45
+ current = current[tag_name].last
46
+ else
47
+ current[tag_name] = parameters
48
+ current = current[tag_name]
49
+ end
50
+ end
51
+
52
+ elsif close_tag
53
+ parent = current[:parent]
54
+ current.delete( :parent )
55
+ current = parent unless parent.nil?
56
+ elsif cdata
57
+ cdata.strip!
58
+ current[:cdata] = cdata unless cdata.empty?
59
+ end
60
+ end
61
+
62
+ return normalize_cdata( current )
63
+ end
64
+
65
+ def self.normalize_cdata(branch)
66
+ if branch.class == Array
67
+ branch.collect do |item|
68
+ normalize_cdata( item )
69
+ end
70
+ elsif branch.class == Hash && branch[:cdata].nil?
71
+ branch.inject( {} ) do |hash, key_value|
72
+ key, value = key_value
73
+ value = normalize_cdata( value )
74
+ hash[key] = value
75
+ hash
76
+ end
77
+ else
78
+ if branch[:cdata] && branch.size == 1
79
+ branch[:cdata]
80
+ else
81
+ branch
82
+ end
83
+ end
84
+ end
85
+
86
+ def self.dump(object, indent = 0)
87
+ ' ' * indent << dump_object(object, indent).strip
88
+ end
89
+
90
+ def self.dump_object(object, indent = 0)
91
+ xml = ''
92
+
93
+ if object.class == Object
94
+ object = object.instance_variables.inject( {} ) { |hash, var| hash[var.gsub('@', '')] = object.instance_variable_get(var); hash }
95
+ end
96
+
97
+ case object
98
+ when Array
99
+ object.each do |value|
100
+ xml << indenter(indent) << "<value>" << dump_object( value, indent + 1 ) << "</value>"
101
+ end
102
+ xml << indenter(indent - 1)
103
+ when Hash
104
+ object.each do |key, value|
105
+ xml << indenter(indent) << "<#{key}>" << dump_object( value, indent + 1 ) << "</#{key}>"
106
+ end
107
+ xml << indenter(indent - 1)
108
+ else
109
+ xml << object.to_s
110
+ end
111
+
112
+ return xml
113
+ end
114
+
115
+ def self.indenter(indent = 0)
116
+ "\n" << ' ' * indent
117
+ end
118
+ end
119
+
@@ -0,0 +1,63 @@
1
+ # Copyright (c) 2005 Norman Timmler (inlet media e.K., Hamburg, Germany)
2
+ # All rights reserved.
3
+ #
4
+ # Redistribution and use in source and binary forms, with or without
5
+ # modification, are permitted provided that the following conditions
6
+ # are met:
7
+ # 1. Redistributions of source code must retain the above copyright
8
+ # notice, this list of conditions and the following disclaimer.
9
+ # 2. Redistributions in binary form must reproduce the above copyright
10
+ # notice, this list of conditions and the following disclaimer in the
11
+ # documentation and/or other materials provided with the distribution.
12
+ # 3. The name of the author may not be used to endorse or promote products
13
+ # derived from this software without specific prior written permission.
14
+ #
15
+ # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16
+ # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17
+ # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18
+ # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19
+ # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20
+ # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21
+ # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22
+ # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23
+ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24
+ # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
+
26
+ class MiYAML
27
+
28
+ def self.dump(object, options = {})
29
+ options = { :indent => 0, :boundaries => true }.merge( options )
30
+
31
+ out = (options[:boundaries] ? "---\n" : '')
32
+ out << dump_object(object, options[:indent]).strip
33
+ out << (options[:boundaries] ? "\n...\n" : '')
34
+ out
35
+ end
36
+
37
+ def self.dump_object(object, indent = 0)
38
+ yaml = ''
39
+
40
+ if object.class == Object
41
+ object = object.instance_variables.inject( {} ) { |hash, var| hash[var.gsub('@', '')] = object.instance_variable_get(var); hash }
42
+ end
43
+
44
+ case object
45
+ when Array
46
+ object.each do |value|
47
+ yaml << indenter(indent) << '- ' << dump_object( value, indent + 1 )
48
+ end
49
+ when Hash
50
+ object.each do |key, value|
51
+ yaml << indenter(indent) << "#{key}: " << dump_object( value, indent + 1 )
52
+ end
53
+ else
54
+ yaml << object.to_s
55
+ end
56
+
57
+ return yaml
58
+ end
59
+
60
+ def self.indenter(indent = 0)
61
+ "\n" << ' ' * indent
62
+ end
63
+ end