depix 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,42 @@
1
+ require File.dirname(__FILE__) + '/structs'
2
+
3
+ module Depix
4
+ CompactInfo = FileInfo.only(
5
+ :magic,
6
+ :ditto_key,
7
+ :filename,
8
+ :timestamp
9
+ )
10
+
11
+
12
+ CompactFilmInfo = FilmInfo.only(
13
+ :offset,
14
+ :count,
15
+ :frame_position,
16
+ :frame_id,
17
+ :slate
18
+ )
19
+
20
+ CompactOrientation = OrientationInfo.only(
21
+ :filename,
22
+ :timestamp
23
+ )
24
+
25
+ CompactTelevision = TelevisionInfo.only(
26
+ :time_code,
27
+ :user_bits,
28
+ :field_number
29
+ )
30
+
31
+
32
+ # A version of the DPX structure that only accounts for the values that change per frame if the ditto_key is set to 1
33
+ class CompactDPX < Dict
34
+ inner :file, CompactInfo, :desc => "File information, only frame-transient values"
35
+
36
+ inner :image, ImageInfo.filler
37
+
38
+ inner :orientation, OrientationInfo, :desc => "Orientation, only frame-transient values"
39
+ inner :film, CompactFilmInfo, :desc => "Film industry info, only frame-dependent values"
40
+ inner :television, CompactTelevision, :desc => "TV industry info, only frame-dependent values"
41
+ end
42
+ end
data/lib/depix/dict.rb ADDED
@@ -0,0 +1,343 @@
1
+ module Depix
2
+
3
+ #:stopdoc:
4
+ class Field
5
+ attr_accessor :name, :length, :pattern, :req, :desc, :rtype
6
+ alias_method :req?, :req
7
+
8
+ # Hash init
9
+ def initialize(opts = {})
10
+ opts.each_pair {|k, v| send(k.to_s + '=', v) }
11
+ end
12
+
13
+ # Emit an unsigned int field
14
+ def self.emit_u32(o = {})
15
+ U32Field.new(o)
16
+ end
17
+
18
+ # Emit a short int field
19
+ def self.emit_u8(o = {})
20
+ U8Field.new(o)
21
+ end
22
+
23
+ # Emit a double int field
24
+ def self.emit_u16(o = {})
25
+ U16Field.new(o)
26
+ end
27
+
28
+ # Emit a char field
29
+ def self.emit_char(o = {})
30
+ opts = {:length => 1}.merge(o)
31
+ CharField.new(opts)
32
+ end
33
+
34
+ # Emit a float field
35
+ def self.emit_r32(o = {})
36
+ R32Field.new(o)
37
+ end
38
+
39
+ # Return a cleaned value
40
+ def clean(v)
41
+ v
42
+ end
43
+
44
+ def explain
45
+ [rtype ? ("(%s)" % rtype) : nil, desc, (req? ? "- required" : nil)].compact.join(' ')
46
+ end
47
+
48
+ # Return the actual values from the stack. The stack will begin on the element we need,
49
+ # so the default consumption is shift
50
+ def consume!(stack)
51
+ clean(stack.shift)
52
+ end
53
+ end
54
+
55
+ class U32Field < Field
56
+ BLANK = 0xFFFFFFFF
57
+
58
+ def pattern
59
+ "N"
60
+ end
61
+
62
+ def length
63
+ 4
64
+ end
65
+
66
+ def clean(value)
67
+ value == BLANK ? nil : value
68
+ end
69
+ end
70
+
71
+ class U8Field < Field
72
+
73
+ BLANK = 0xFF
74
+
75
+ def pattern
76
+ "c"
77
+ end
78
+
79
+ def length
80
+ 1
81
+ end
82
+
83
+ def rtype
84
+ Integer
85
+ end
86
+
87
+ def clean(v)
88
+ v == BLANK ? nil : v
89
+ end
90
+ end
91
+
92
+ class Filler < Field
93
+ def pattern
94
+ "x#{length ? length.to_i : 1}"
95
+ end
96
+
97
+ # Leave the stack alone since we skipped
98
+ def consume(stack)
99
+ nil
100
+ end
101
+ end
102
+
103
+ class U16Field < Field
104
+ BLANK = 0xFFFF
105
+
106
+ def pattern
107
+ "n"
108
+ end
109
+
110
+ def length
111
+ 2
112
+ end
113
+
114
+ def rtype
115
+ Integer
116
+ end
117
+
118
+ def clean(v)
119
+ v == BLANK ? nil : v
120
+ end
121
+ end
122
+
123
+ class R32Field < Field
124
+ def pattern
125
+ "g"
126
+ end
127
+
128
+ def clean(v)
129
+ v.nan? ? nil : v
130
+ end
131
+
132
+ def length
133
+ 4
134
+ end
135
+
136
+ def rtype
137
+ Float
138
+ end
139
+ end
140
+
141
+ class CharField < Field
142
+ BLANK = "\0"
143
+
144
+ def pattern
145
+ "A#{(length || 1).to_i}"
146
+ end
147
+
148
+ def clean(v)
149
+ if v == BLANK
150
+ nil
151
+ else
152
+ cleansed = v.gsub(0xFF.chr, '').gsub(0x00.chr, '')
153
+ cleansed.empty? ? nil : cleansed
154
+ end
155
+ end
156
+
157
+ def rtype
158
+ String
159
+ end
160
+ end
161
+
162
+ # Wrapper for an array structure
163
+ class ArrayField < Field
164
+ attr_accessor :members
165
+ undef :length=, :pattern=
166
+
167
+ def length
168
+ members.inject(0){|_, s| _ + s.length }
169
+ end
170
+
171
+ def pattern
172
+ members.inject(''){|_, s| _ + s.pattern }
173
+ end
174
+
175
+ def consume!(stack)
176
+ members.map{|m| m.consume!(stack)}
177
+ end
178
+
179
+ def rtype
180
+ Array
181
+ end
182
+
183
+ def explain
184
+ return 'Empty array' if (!members || members.empty?)
185
+ tpl = "(Array of %d %s fields)" % [ members.length, members[0].rtype]
186
+ r = (req? ? "- required" : nil)
187
+ [tpl, desc, r].compact.join(' ')
188
+ end
189
+ end
190
+
191
+ # Wrapper for a contained structure
192
+ class InnerField < Field
193
+ attr_accessor :cast
194
+ undef :length=, :pattern=
195
+
196
+ def length
197
+ cast.length
198
+ end
199
+
200
+ def pattern
201
+ cast.pattern
202
+ end
203
+
204
+ def consume!(stack)
205
+ cast.consume!(stack)
206
+ end
207
+
208
+ def rtype
209
+ cast
210
+ end
211
+ end
212
+
213
+ # Base class for a struct. Could also be implemented as a module actually
214
+ class Dict
215
+ DEF_OPTS = { :req => false, :desc => nil }
216
+
217
+ class << self
218
+
219
+ # Get the array of fields defined in this struct
220
+ def fields
221
+ @fields ||= []
222
+ end
223
+
224
+ # Define a 4-byte unsigned integer
225
+ def u32(name, *extras)
226
+ count, opts = count_and_opts_from(extras)
227
+ attr_accessor name
228
+ fields << Field.emit_u32( {:name => name }.merge(opts) )
229
+ end
230
+
231
+ # Define a double-width unsigned integer
232
+ def u16(name, *extras)
233
+ count, opts = count_and_opts_from(extras)
234
+ attr_accessor name
235
+ fields << Field.emit_u16( {:name => name }.merge(opts) )
236
+ end
237
+
238
+
239
+ # Define a small unsigned integer
240
+ def u8(name, *extras)
241
+ count, opts = count_and_opts_from(extras)
242
+ attr_accessor name
243
+ fields << Field.emit_u8( {:name => name }.merge(opts) )
244
+ end
245
+
246
+ # Define a real number
247
+ def r32(name, *extras)
248
+ count, opts = count_and_opts_from(extras)
249
+ attr_accessor name
250
+ fields << Field.emit_r32( {:name => name}.merge(opts) )
251
+ end
252
+
253
+ # Define an array of values
254
+ def array(name, mapped_to, *extras)
255
+ count, opts = count_and_opts_from(extras)
256
+ attr_accessor name
257
+
258
+ a = ArrayField.new({:name => name}.merge(opts))
259
+ a.members = if mapped_to.is_a?(Class) # Array of structs
260
+ [InnerField.new(:cast => mapped_to)] * count
261
+ else
262
+ [Field.send("emit_#{mapped_to}")] * count
263
+ end
264
+ fields << a
265
+ end
266
+
267
+ # Define a nested struct
268
+ def inner(name, mapped_to, *extras)
269
+ count, opts = count_and_opts_from(extras)
270
+ attr_accessor name
271
+ fields << InnerField.new({:name => name, :cast => mapped_to}.merge(opts))
272
+ end
273
+
274
+ # Define a char field
275
+ def char(name, *extras)
276
+ count, opts = count_and_opts_from(extras)
277
+ attr_accessor name
278
+ fields << Field.emit_char( {:name => name, :length => count}.merge(opts) )
279
+ end
280
+
281
+ # Get the pattern that will be used to unpack this structure and all of it's descendants
282
+ def pattern
283
+ fields.map{|f| f.pattern }.join
284
+ end
285
+
286
+ # How many bytes are needed to complete this structure
287
+ def length
288
+ fields.inject(0){|_, s| _ + s.length }
289
+ end
290
+
291
+ # Consume a stack of unpacked values, letting each field decide how many to consume
292
+ def consume!(stack_of_unpacked_values)
293
+ new_item = new
294
+ @fields.each do | field |
295
+ new_item.send("#{field.name}=", field.consume!(stack_of_unpacked_values)) unless field.name.nil?
296
+ end
297
+ new_item
298
+ end
299
+
300
+ # Apply this structure to data in the string, returning an instance of this structure with fields completed
301
+ def apply!(string)
302
+ consume!(string.unpack(pattern))
303
+ end
304
+
305
+ # Get a class that would parse just the same, preserving only the fields passed in the array. This speeds
306
+ # up parsing because we only extract and conform the fields that we need
307
+ def only(*field_names)
308
+ distillate = fields.inject([]) do | m, f |
309
+ if field_names.include?(f.name) # preserve
310
+ m.push(f)
311
+ else # create filler
312
+ unless m[-1].is_a?(Filler)
313
+ m.push(Filler.new(:length => f.length))
314
+ else
315
+ m[-1].length += f.length
316
+ end
317
+ m
318
+ end
319
+ end
320
+
321
+ anon = Class.new(self)
322
+ anon.fields.replace(distillate)
323
+ anon
324
+ end
325
+
326
+ # Get an opaque struct based on this one, that will consume exactly as many bytes as this
327
+ # structure would occupy, but discard them instead
328
+ def filler
329
+ only([])
330
+ end
331
+
332
+ private
333
+
334
+ # extract_options! on a diet
335
+ def count_and_opts_from(args)
336
+ options, count = (args[-1].is_a?(Hash) ? DEF_OPTS.merge(args.pop) : DEF_OPTS), (args.shift || 1)
337
+ [count, options]
338
+ end
339
+ end
340
+ end
341
+
342
+ #:startdoc:
343
+ end
@@ -0,0 +1,43 @@
1
+ module Depix
2
+ COLORIMETRIC = {
3
+ :UserDefined => 0,
4
+ :PrintingDensity => 1,
5
+ :Linear => 2,
6
+ :Logarithmic => 3,
7
+ :UnspecifiedVideo => 4,
8
+ :SMTPE_274M => 5,
9
+ :ITU_R709 => 6,
10
+ :ITU_R601_625L => 7,
11
+ :ITU_R601_525L => 8,
12
+ :NTSCCompositeVideo => 9,
13
+ :PALCompositeVideo => 10,
14
+ :ZDepthLinear => 11,
15
+ :DepthHomogeneous => 12
16
+ }
17
+
18
+ COMPONENT_TYPE = {
19
+ :Undefined => 0,
20
+ :Red => 1,
21
+ :Green => 2,
22
+ :Blue => 3,
23
+ :Alpha => 4,
24
+ :Luma => 6,
25
+ :ColorDifferenceCbCr => 7,
26
+ :Depth => 8,
27
+ :CompositeVideo => 9,
28
+ :RGB => 50,
29
+ :RGBA => 51,
30
+ :ABGR => 52,
31
+ :CbYCrY422 => 100,
32
+ :CbYACrYA4224 => 101,
33
+ :CbYCr444 => 102,
34
+ :CbYCrA4444 => 103,
35
+ :UserDef2Element => 150,
36
+ :UserDef3Element => 151,
37
+ :UserDef4Element => 152,
38
+ :UserDef5Element => 153,
39
+ :UserDef6Element => 154,
40
+ :UserDef7Element => 155,
41
+ :UserDef8Element => 156,
42
+ }
43
+ end
@@ -1,45 +1,13 @@
1
1
  # Generates an RDoc description of the DPX structs from the structs.rb file
2
- class Formatter #:nodoc:
2
+ class RdocExplainer #:nodoc:
3
3
  attr_accessor :io, :attr_template, :struct_template
4
4
 
5
- def initialize
6
- @io = STDOUT
7
- @attr_template = "%s%s (%s)"
8
- @struct_template = "%s%s (which is a hash with the following elements):"
9
- @array_template = "%s%s (array , %d members):"
10
- @padding = ' '
11
- end
12
-
13
- def explain_struct(struct, padding = '') #:nodoc:
14
- struct.each do | e |
15
- key, cast, len = e
16
- if cast.is_a?(Depix::Structs::Struct)
17
- @io.puts( @struct_template % [padding, key, len])
18
- explain_struct(cast, padding + @padding)
19
- elsif cast.is_a?(Array) # Repeats
20
- @io.puts( @array_template % [padding, key, cast.size])
21
- inner_struct = cast[0]
22
- ikey, icast, ilen = inner_struct
23
- if icast.is_a?(Depix::Structs::Struct)
24
- explain_struct(icast, padding + @padding)
25
- else
26
- @io.puts( @attr_template % [padding, '', icast, ilen])
27
- end
28
- else
29
- @io.puts( @attr_template % [padding, key, cast, len])
30
- end
31
- end
32
- end
33
- end
34
-
35
- class RdocExplainer < Formatter #:nodoc:
36
5
  TPL = <<eof
37
6
  = DPX header structure description
38
7
 
39
- DPX metadata gets returned as a hash containing other nested hashes. You can address hash keys by symbol, string
40
- and method name
41
-
42
- meta.file.magic # same as meta[:file][:magic]
8
+ DPX metadata gets returned as a Depix::DPX object with nested properties.
9
+
10
+ meta.file.magic # => "SDPX"
43
11
 
44
12
  == Metadata structure
45
13
 
@@ -47,16 +15,45 @@ and method name
47
15
  eof
48
16
 
49
17
  def initialize
50
- super
18
+ @padding = ' '
51
19
  @attr_template = "%s* <tt>%s</tt> %s"
52
- @struct_template = "%s* <tt>%s</tt> hash of"
53
- @array_template = "%s* <tt>%s</tt> (array , %d members):"
20
+ @struct_template = "%s* <tt>%s</tt> %s:"
21
+ @array_template = "%s* <tt>%s</tt> %s:"
54
22
 
55
23
  end
56
24
 
57
25
  def get_rdoc_for(struct)
58
26
  @io = StringIO.new
59
- explain_struct(Depix::Structs::DPX_INFO)
27
+ explain_struct(struct)
60
28
  TPL % @io.string
61
29
  end
30
+
31
+ include Depix
32
+
33
+ def explain_struct(struct, padding = '') #:nodoc:
34
+ struct.fields.each do | e |
35
+ if e.is_a?(InnerField)
36
+
37
+ @io.puts( @struct_template % [padding, e.name, e.explain])
38
+ explain_struct(e.rtype, padding + @padding)
39
+
40
+ elsif e.is_a?(ArrayField)
41
+
42
+ @io.puts( @array_template % [padding, e.name, e.explain])
43
+
44
+ inner_struct = e.members[0]
45
+
46
+ if inner_struct.is_a?(InnerField)
47
+ explain_struct(inner_struct.rtype, padding + @padding)
48
+ end
49
+ else
50
+ explain_attr(padding, e)
51
+ end
52
+ end
53
+ end
54
+
55
+ def explain_attr(padding, e)
56
+ type_name = e.rtype ? "(#{e.rtype})" : nil
57
+ @io.puts( @attr_template % [padding, e.name, e.explain])
58
+ end
62
59
  end