depix 1.0.1 → 1.0.2

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,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