source: extensions/gsdl-video/trunk/installed/cmdline/lib/ruby/site_ruby/1.8/flvtool2/base.rb@ 18425

Last change on this file since 18425 was 18425, checked in by davidb, 15 years ago

Video extension to Greenstone

File size: 9.8 KB
Line 
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
27require 'flv'
28require 'mixml'
29require 'miyaml'
30
31module 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
297end
Note: See TracBrowser for help on using the repository browser.