flvtool2 1.0.6

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.
@@ -0,0 +1,120 @@
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
+ require 'flv/core_extensions'
27
+ require 'flv/stream'
28
+
29
+
30
+ module FLV
31
+
32
+ class FLVTag
33
+
34
+ AUDIO = 8
35
+ VIDEO = 9
36
+ META = 18
37
+ UNDEFINED = 0
38
+
39
+ attr_accessor :tag_type,
40
+ :timestamp,
41
+ :byte_offset
42
+
43
+ def initialize(stream = nil)
44
+ @tag_type = UNDEFINED
45
+ @byte_offset = nil
46
+
47
+ unless stream.nil?
48
+ data_size = stream.read__UI24
49
+ @timestamp = stream.read__UI24
50
+ stream.read__UI32
51
+ @data = stream.read(data_size)
52
+ else
53
+ @timestamp = 0
54
+ @data = ''
55
+ end
56
+ after_initialize(stream.nil?) if respond_to? :after_initialize
57
+ end
58
+
59
+ def size
60
+ # header(11) + body(data_size)
61
+ 11 + data_size
62
+ end
63
+
64
+ def name
65
+ 'Unknown Tag'
66
+ end
67
+
68
+ def data
69
+ @data
70
+ end
71
+
72
+ def data_size
73
+ data.length
74
+ end
75
+
76
+ def serialize(stream)
77
+ stream.write__UI8 tag_type
78
+ stream.write__UI24 data_size
79
+ stream.write__UI24 timestamp
80
+ stream.write__UI32 0
81
+ stream.write__STRING data
82
+ end
83
+
84
+ def info
85
+ "#{name}: timestamp #{timestamp}, size #{size}, data size #{data_size}"
86
+ end
87
+
88
+ def inspect
89
+ out = ["tag: #{self.class}"]
90
+ out << "timestamp: #{@timestamp}"
91
+ out << "size: #{size}"
92
+ out << "data_size: #{data_size}"
93
+ out
94
+ end
95
+
96
+ def self.type2name(type)
97
+ case type
98
+ when AUDIO
99
+ 'audio'
100
+ when VIDEO
101
+ 'video'
102
+ when META
103
+ 'meta'
104
+ when UNDEFINED
105
+ 'undefined'
106
+ else
107
+ "unknown(#{type})"
108
+ end
109
+ end
110
+
111
+ private
112
+ def bit2uint(sequence)
113
+ int = 0
114
+ sequence.split(//).each_with_index do |character, i|
115
+ int += 2 ** (sequence.length - i - 1) if character == '1'
116
+ end
117
+ int
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,114 @@
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
+ require 'flv/amf_string_buffer'
27
+
28
+ module FLV
29
+
30
+ class FLVVideoTag < FLVTag
31
+
32
+ H263VIDEOPACKET = 2
33
+ SCREENVIDEOPACKET = 3
34
+ ON2VP6 = 4
35
+
36
+ KEYFRAME = 1
37
+ INTERFRAME = 2
38
+ DISPOSABLEINTERFRAME = 3
39
+
40
+ attr_reader :frame_type,
41
+ :codec_id,
42
+ :width,
43
+ :height
44
+
45
+ def after_initialize(new_object)
46
+ @tag_type = VIDEO
47
+ read_header
48
+ end
49
+
50
+ def name
51
+ case frame_type
52
+ when KEYFRAME
53
+ 'Video Tag (Keyframe)'
54
+ when INTERFRAME
55
+ 'Video Tag (Interframe)'
56
+ when DISPOSABLEINTERFRAME
57
+ 'Video Tag (disposable Interframe)'
58
+ else
59
+ 'Video Tag'
60
+ end
61
+ end
62
+
63
+ def keyframe?
64
+ frame_type == KEYFRAME
65
+ end
66
+
67
+ def interframe?
68
+ frame_type == INTERFRAME || frame_type == DISPOSABLEINTERFRAME
69
+ end
70
+
71
+ def read_header
72
+ data_stream = AMFStringBuffer.new(@data)
73
+
74
+ # the sequence is swaped in the swf-file-format description
75
+ # frame_type <-> codec_id (description: 1. codec_id, 2. frame_type)
76
+ codec_id_and_frame_type = data_stream.read__UI8
77
+ @frame_type = codec_id_and_frame_type >> 4
78
+ @codec_id = codec_id_and_frame_type & 0xf
79
+
80
+ bit_sequence = data_stream.read(9).unpack('B72').to_s
81
+
82
+ if @codec_id == H263VIDEOPACKET
83
+ @width, @height = case bit2uint bit_sequence[30,3]
84
+ when 0
85
+ [bit2uint(bit_sequence[33,8]), bit2uint(bit_sequence[41,8])]
86
+ when 1
87
+ [bit2uint(bit_sequence[33,16]), bit2uint(bit_sequence[49,16])]
88
+ when 2
89
+ [352, 288]
90
+ when 3
91
+ [176, 144]
92
+ when 4
93
+ [128, 96]
94
+ when 5
95
+ [320, 240]
96
+ when 6
97
+ [160, 120]
98
+ end
99
+ elsif @codec_id == SCREENVIDEOPACKET
100
+ @width, @height = bit2uint(bit_sequence[4,12]), bit2uint(bit_sequence[16,12])
101
+ end
102
+ end
103
+
104
+ def inspect
105
+ out = super
106
+ out << "frame_type: #{%w{ Keyframe Interframe DisposableInterframe }[@frame_type]}"
107
+ out << "codec_id: #{@codec_id}"
108
+ out << "width: #{@width}"
109
+ out << "height: #{@height}"
110
+ out << "data_size: #{data_size}"
111
+ out
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,230 @@
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
+ require 'flvtool2/version'
27
+ require 'flvtool2/base'
28
+
29
+ module FLVTool2
30
+
31
+ SHELL_COMMAND_NAME = (RUBY_PLATFORM =~ /win32/) ? 'flvtool2.exe' : 'flvtool2'
32
+ SWITCHES = %w{ s v r p x c i o k t n l a }
33
+ COMMANDS = %w{ U C P D A V }
34
+
35
+ def self.parse_arguments
36
+ options = {}
37
+ options[:commands] = []
38
+ options[:metadatacreator] = "inlet media FLVTool2 v#{PROGRAMM_VERSION.join('.')} - http://www.inlet-media.de/flvtool2"
39
+ options[:metadata] = {}
40
+ options[:in_path] = nil
41
+ options[:in_pipe] = false
42
+ options[:out_path] = nil
43
+ options[:out_pipe] = false
44
+ options[:simulate] = false
45
+ options[:verbose] = false
46
+ options[:recursive] = false
47
+ options[:preserve] = false
48
+ options[:xml] = false
49
+ options[:compatibility_mode] = false
50
+ options[:in_point] = nil
51
+ options[:out_point] = nil
52
+ options[:keyframe_mode] = false
53
+ options[:tag_file] = nil
54
+ options[:tag_number] = nil
55
+ options[:stream_log] = false
56
+ options[:collapse] = false
57
+
58
+ while (arg = ARGV.shift)
59
+ case arg
60
+ when /^-([a-zA-Z0-9]+?):(.+)$/
61
+ options[:metadata][$1] = $2
62
+ when /^-([a-zA-Z0-9]+?)#([0-9]+)$/
63
+ options[:metadata][$1] = $2.to_f
64
+ when /^-([a-zA-Z0-9]+?)@(\d{4,})-(\d{2,})-(\d{2,}) (\d{2,}):(\d{2,}):(\d{2,})$/
65
+ options[:metadata][$1] = Time.local($2, $3, $4, $5, $6, $7)
66
+ when /^-(.+)$/
67
+ $1.split(//).flatten.each do |switch|
68
+ case switch
69
+ when 's'
70
+ options[:simulate] = true
71
+ when 'v'
72
+ options[:verbose] = true
73
+ when 'r'
74
+ options[:recursive] = true
75
+ when 'p'
76
+ options[:preserve] = true
77
+ when 'x'
78
+ options[:xml] = true
79
+ when 'c'
80
+ options[:compatibility_mode] = true
81
+ when 'i'
82
+ options[:in_point] = ARGV.shift.to_i
83
+ when 'o'
84
+ options[:out_point] = ARGV.shift.to_i
85
+ when 'k'
86
+ options[:keyframe_mode] = true
87
+ when 't'
88
+ options[:tag_file] = ARGV.shift
89
+ when 'n'
90
+ options[:tag_number] = ARGV.shift.to_i
91
+ when 'l'
92
+ options[:stream_log] = true
93
+ when 'a'
94
+ options[:collapse] = true
95
+ when 'U'
96
+ options[:commands] << :update
97
+ when 'P'
98
+ options[:commands] << :print
99
+ when 'C'
100
+ options[:commands] << :cut
101
+ when 'D'
102
+ options[:commands] << :debug
103
+ when 'A'
104
+ options[:commands] << :add
105
+ when 'H'
106
+ options[:commands] << :help
107
+ when 'V'
108
+ options[:commands] << :version
109
+ end
110
+ end
111
+ when /^([^-].*)$/
112
+ if options[:in_path].nil?
113
+ options[:in_path] = $1
114
+ if options[:in_path].downcase =~ /stdin|pipe/
115
+ options[:in_pipe] = true
116
+ options[:in_path] = 'pipe'
117
+ else
118
+ options[:in_path] = File.expand_path( options[:in_path] )
119
+ end
120
+ else
121
+ options[:out_path] = $1
122
+ if options[:out_path].downcase =~ /stdout|pipe/
123
+ options[:out_pipe] = true
124
+ options[:out_path] = 'pipe'
125
+ else
126
+ options[:out_path] = File.expand_path( options[:out_path] )
127
+ end
128
+ end
129
+ end
130
+ end
131
+
132
+ return options
133
+ end
134
+
135
+ def self.validate_options( options )
136
+ if options[:commands].empty?
137
+ show_usage
138
+ exit 0
139
+ end
140
+
141
+ options[:commands].each do |command|
142
+ case command
143
+ when :print
144
+ if options[:out_pipe]
145
+ throw_error "Could not use print command in conjunction with output piping or redirection"
146
+ exit 1
147
+ end
148
+ when :debug
149
+ if options[:out_pipe]
150
+ throw_error "Could not use debug command in conjunction with output piping or redirection"
151
+ exit 1
152
+ end
153
+ when :help
154
+ show_usage
155
+ exit 0
156
+ when :version
157
+ show_version
158
+ exit 0
159
+ end
160
+ end
161
+ options
162
+ end
163
+
164
+ def self.execute!(options)
165
+ if options[:commands].include? :help
166
+ show_usage
167
+ else
168
+ FLVTool2::Base::execute!( options )
169
+ end
170
+ end
171
+
172
+ def self.show_version
173
+ puts "FLVTool2 #{version}"
174
+ end
175
+
176
+ def self.show_usage
177
+ self.show_version
178
+ puts "Copyright (c) 2005-2007 Norman Timmler (inlet media e.K., Hamburg, Germany)\n"
179
+ puts "Get the latest version from http://www.inlet-media.de/flvtool2\n"
180
+ puts "This program is published under the BSD license.\n"
181
+ puts "\n"
182
+ puts "Usage: #{SHELL_COMMAND_NAME} [-#{COMMANDS.sort.join}#{SWITCHES.sort.join}]... [-key:value]... in-path|stdin [out-path|stdout]\n"
183
+ puts "\n"
184
+ puts "If out-path is omitted, in-path will be overwritten.\n"
185
+ puts "In-path can be a single file, or a directory. If in-path is a directory,\n"
186
+ puts "out-path has to be likewise, or can be omitted. Directory recursion\n"
187
+ puts "is controlled by the -r switch. You can use stdin and stdout keywords\n"
188
+ puts "as in- and out-path for piping or redirecting.\n"
189
+ puts "\n"
190
+ puts "Chain commands like that: -UP (updates FLV file than prints out meta data)\n"
191
+ puts "\n"
192
+ puts "Commands:\n"
193
+ puts " -A Adds tags from -t tags-file\n"
194
+ puts " -C Cuts file using -i inpoint and -o outpoint\n"
195
+ puts " -D Debugs file (writes a lot to stdout)\n"
196
+ puts " -H Helpscreen will be shown\n"
197
+ puts " -P Prints out meta data to stdout\n"
198
+ puts " -U Updates FLV with an onMetaTag event\n"
199
+ puts "\n"
200
+ puts "Switches:\n"
201
+ puts " -a Collapse space between cutted regions\n"
202
+ puts " -c Compatibility mode calculates some onMetaTag values different\n"
203
+ puts " -key:value Key-value-pair for onMetaData tag (overwrites generated values)\n"
204
+ puts " -i timestamp Inpoint for cut command in miliseconds\n"
205
+ puts " -k Keyframe mode slides onCuePoint(navigation) tags added by the\n"
206
+ puts " add command to nearest keyframe position\n"
207
+ puts " -l Logs FLV stream reading to stream.log in current directory\n"
208
+ puts " -n Number of tag to debug\n"
209
+ puts " -o timestamp Outpoint for cut command in miliseconds\n"
210
+ puts " -p Preserve mode only updates FLVs that have not been processed\n"
211
+ puts " before\n"
212
+ puts " -r Recursion for directory processing\n"
213
+ puts " -s Simulation mode never writes FLV data to out-path\n"
214
+ puts " -t path Tagfile (MetaTags written in XML)\n"
215
+ puts " -v Verbose mode\n"
216
+ puts " -x XML mode instead of YAML mode\n"
217
+ puts "\n"
218
+ puts "REPORT BUGS at http://projects.inlet-media.de/flvtool2"
219
+ puts "Powered by Riva VX, http://rivavx.com\n"
220
+ end
221
+
222
+ def self.throw_error(error)
223
+ puts "ERROR: #{error}"
224
+ end
225
+ end
226
+
227
+
228
+ FLVTool2::execute!( FLVTool2::validate_options( FLVTool2::parse_arguments ) )
229
+ exit 0
230
+