format_parser 2.3.0 → 2.4.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,632 @@
1
+ require 'matrix'
2
+ require 'spec_helper'
3
+
4
+ describe FormatParser::ISOBaseMediaFileFormat::Utils do
5
+ include FormatParser::ISOBaseMediaFileFormat::Utils
6
+ Box = FormatParser::ISOBaseMediaFileFormat::Box
7
+
8
+ describe '.dimensions' do
9
+ context 'when no moov box' do
10
+ let(:box_tree) { [Box.new('ftyp', 0, 16)] }
11
+
12
+ it 'returns nil' do
13
+ expect(dimensions(box_tree)).to eq(nil)
14
+ end
15
+ end
16
+
17
+ context 'when no video trak boxes' do
18
+ let(:box_tree) do
19
+ [
20
+ Box.new('moov', 0, 0, nil, [
21
+ Box.new('trak', 0, 0),
22
+ Box.new('trak', 0, 0, nil, [
23
+ Box.new('hdlr', 0, 0, { handler_type: 'soun' }),
24
+ ]),
25
+ Box.new('trak', 0, 0, nil, [
26
+ Box.new('hdlr', 0, 0, { component_type: 'mhlr', component_subtype: 'soun' }),
27
+ ])
28
+ ])
29
+ ]
30
+ end
31
+
32
+ it 'returns nil' do
33
+ expect(dimensions(box_tree)).to eq(nil)
34
+ end
35
+ end
36
+
37
+ context 'when no video tkhd boxes' do
38
+ let(:box_tree) do
39
+ [
40
+ Box.new('moov', 0, 0, nil, [
41
+ Box.new('trak', 0, 0, nil, [
42
+ Box.new('hdlr', 0, 0, { handler_type: 'soun' }),
43
+ Box.new('tkhd', 0, 0),
44
+ ]),
45
+ Box.new('trak', 0, 0, nil, [
46
+ Box.new('hdlr', 0, 0, { handler_type: 'vide' }),
47
+ ]),
48
+ Box.new('trak', 0, 0, nil, [
49
+ Box.new('hdlr', 0, 0, { component_type: 'mhlr', component_subtype: 'vide' }),
50
+ ])
51
+ ])
52
+ ]
53
+ end
54
+
55
+ it 'returns nil' do
56
+ expect(dimensions(box_tree)).to eq(nil)
57
+ end
58
+ end
59
+
60
+ context 'when dimensions missing' do
61
+ let(:box_tree) do
62
+ [
63
+ Box.new('moov', 0, 0, nil, [
64
+ Box.new('trak', 0, 0, nil, [
65
+ Box.new('hdlr', 0, 0, { handler_type: 'vide' }),
66
+ Box.new('tkhd', 0, 0, { height: 100 })
67
+ ]),
68
+ ])
69
+ ]
70
+ end
71
+
72
+ it 'returns nil' do
73
+ expect(dimensions(box_tree)).to eq(nil)
74
+ end
75
+ end
76
+
77
+ context 'when movie matrix missing' do
78
+ let(:box_tree) do
79
+ [
80
+ Box.new('moov', 0, 0, nil, [
81
+ Box.new('trak', 0, 0, nil, [
82
+ Box.new('hdlr', 0, 0, { handler_type: 'vide' }),
83
+ Box.new('tkhd', 0, 0, {
84
+ height: 100,
85
+ width: 200,
86
+ matrix: Matrix[[2, 0, 0], [0, 2, 0], [0, 0, 2]]
87
+ })
88
+ ]),
89
+ ])
90
+ ]
91
+ end
92
+
93
+ it 'defaults to identity matrix' do
94
+ expect(dimensions(box_tree)).to eq([400, 200])
95
+ end
96
+ end
97
+
98
+ context 'when track matrix missing' do
99
+ let(:box_tree) do
100
+ [
101
+ Box.new('moov', 0, 0, nil, [
102
+ Box.new('mvhd', 0, 0, { matrix: Matrix[[2, 0, 0], [0, 2, 0], [0, 0, 2]] }),
103
+ Box.new('trak', 0, 0, nil, [
104
+ Box.new('hdlr', 0, 0, { handler_type: 'vide' }),
105
+ Box.new('tkhd', 0, 0, { height: 100, width: 200 })
106
+ ]),
107
+ ])
108
+ ]
109
+ end
110
+
111
+ it 'defaults to identity matrix' do
112
+ expect(dimensions(box_tree)).to eq([400, 200])
113
+ end
114
+ end
115
+
116
+ context 'when multiple tracks' do
117
+ let(:box_tree) do
118
+ [
119
+ Box.new('moov', 0, 0, nil, [
120
+ Box.new('mvhd', 0, 0, { matrix: Matrix[[2, 0, 0], [0, 2, 0], [0, 0, 2]] }),
121
+ Box.new('trak', 0, 0, nil, [
122
+ Box.new('hdlr', 0, 0, { handler_type: 'vide' }),
123
+ Box.new('tkhd', 0, 0, {
124
+ height: 1000,
125
+ })
126
+ ]),
127
+ Box.new('trak', 0, 0, nil, [
128
+ Box.new('hdlr', 0, 0, { handler_type: 'vide' }),
129
+ Box.new('tkhd', 0, 0, {
130
+ height: 200,
131
+ width: 100,
132
+ matrix: Matrix[[0, 3, 0], [3, 0, 0], [0, 0, 3]]
133
+ })
134
+ ]),
135
+ Box.new('trak', 0, 0, nil, [
136
+ Box.new('hdlr', 0, 0, { component_type: 'mhlr', component_subtype: 'vide' }),
137
+ Box.new('tkhd', 0, 0, {
138
+ height: 200,
139
+ width: 100,
140
+ matrix: Matrix[[2, 0, 0], [0, 2, 0], [0, 0, 2]]
141
+ })
142
+ ]),
143
+ ])
144
+ ]
145
+ end
146
+
147
+ it 'correctly calculates dimensions' do
148
+ expect(dimensions(box_tree)).to eq([1200, 800])
149
+ end
150
+ end
151
+ end
152
+
153
+ describe '.duration' do
154
+ context 'when no moov box' do
155
+ let(:box_tree) { [Box.new('ftyp', 0, 16)] }
156
+
157
+ it 'returns nil' do
158
+ expect(duration(box_tree)).to eq(nil)
159
+ end
160
+ end
161
+
162
+ context 'when no mvhd box' do
163
+ let(:box_tree) { [Box.new('moov', 0, 0)] }
164
+
165
+ it 'returns nil' do
166
+ expect(duration(box_tree)).to eq(nil)
167
+ end
168
+ end
169
+
170
+ context 'when no duration' do
171
+ let(:box_tree) do
172
+ [
173
+ Box.new('moov', 0, 0, nil, [
174
+ Box.new('mvhd', 0, 0, { timescale: 1 })
175
+ ])
176
+ ]
177
+ end
178
+
179
+ it 'returns nil' do
180
+ expect(duration(box_tree)).to eq(nil)
181
+ end
182
+ end
183
+
184
+ context 'when no timescale' do
185
+ let(:box_tree) do
186
+ [
187
+ Box.new('moov', 0, 0, nil, [
188
+ Box.new('mvhd', 0, 0, { duration: 1 })
189
+ ])
190
+ ]
191
+ end
192
+
193
+ it 'returns nil' do
194
+ expect(duration(box_tree)).to eq(nil)
195
+ end
196
+ end
197
+
198
+ context 'when timescale and duration' do
199
+ let(:box_tree) do
200
+ [
201
+ Box.new('moov', 0, 0, nil, [
202
+ Box.new('mvhd', 0, 0, { duration: 10, timescale: 2 })
203
+ ])
204
+ ]
205
+ end
206
+
207
+ it 'correctly calculates duration' do
208
+ expect(duration(box_tree)).to eq(5)
209
+ end
210
+ end
211
+ end
212
+
213
+ describe '.frame_rate' do
214
+ context 'when no moov box' do
215
+ let(:box_tree) { [Box.new('ftyp', 0, 16)] }
216
+
217
+ it 'returns nil' do
218
+ expect(frame_rate(box_tree)).to eq(nil)
219
+ end
220
+ end
221
+
222
+ context 'when no video trak boxes' do
223
+ let(:box_tree) do
224
+ [
225
+ Box.new('moov', 0, 0, nil, [
226
+ Box.new('trak', 0, 0),
227
+ Box.new('trak', 0, 0, nil, [
228
+ Box.new('hdlr', 0, 0, { handler_type: 'soun' }), # Audio - should be ignored
229
+ Box.new('mdia', 0, 0, nil, [
230
+ Box.new('mdhd', 0, 0, { timescale: 30 }),
231
+ Box.new('minf', 0, 0, nil, [
232
+ Box.new('stbl', 0, 0, nil, [
233
+ Box.new('stts', 0, 0, {
234
+ entry_count: 1,
235
+ entries: [
236
+ {
237
+ sample_count: 10,
238
+ sample_delta: 1
239
+ }
240
+ ]
241
+ })
242
+ ])
243
+ ])
244
+ ])
245
+ ]),
246
+ ])
247
+ ]
248
+ end
249
+
250
+ it 'returns nil' do
251
+ expect(frame_rate(box_tree)).to eq(nil)
252
+ end
253
+ end
254
+
255
+ context 'when no mdhd box' do
256
+ let(:box_tree) do
257
+ [
258
+ Box.new('moov', 0, 0, nil, [
259
+ Box.new('trak', 0, 0, nil, [
260
+ Box.new('hdlr', 0, 0, { handler_type: 'vide' }),
261
+ Box.new('mdia', 0, 0, nil, [
262
+ Box.new('minf', 0, 0, nil, [
263
+ Box.new('stbl', 0, 0, nil, [
264
+ Box.new('stts', 0, 0, {
265
+ entry_count: 1,
266
+ entries: [
267
+ {
268
+ sample_count: 10,
269
+ sample_delta: 1
270
+ }
271
+ ]
272
+ })
273
+ ])
274
+ ])
275
+ ])
276
+ ]),
277
+ ])
278
+ ]
279
+ end
280
+
281
+ it 'returns nil' do
282
+ expect(frame_rate(box_tree)).to eq(nil)
283
+ end
284
+ end
285
+
286
+ context 'when no stts box' do
287
+ let(:box_tree) do
288
+ [
289
+ Box.new('moov', 0, 0, nil, [
290
+ Box.new('trak', 0, 0, nil, [
291
+ Box.new('hdlr', 0, 0, { handler_type: 'vide' }),
292
+ Box.new('mdia', 0, 0, nil, [
293
+ Box.new('mdhd', 0, 0, { timescale: 30 }),
294
+ Box.new('minf', 0, 0, nil, [
295
+ Box.new('stbl', 0, 0)
296
+ ])
297
+ ])
298
+ ]),
299
+ ])
300
+ ]
301
+ end
302
+
303
+ it 'returns nil' do
304
+ expect(frame_rate(box_tree)).to eq(nil)
305
+ end
306
+ end
307
+
308
+ context 'when multiple entries' do
309
+ let(:box_tree) do
310
+ [
311
+ Box.new('moov', 0, 0, nil, [
312
+ Box.new('trak', 0, 0),
313
+ Box.new('trak', 0, 0, nil, [
314
+ Box.new('hdlr', 0, 0, { handler_type: 'soun' }), # Audio - should be ignored
315
+ Box.new('mdia', 0, 0, nil, [
316
+ Box.new('mdhd', 0, 0, { timescale: 30 }),
317
+ Box.new('minf', 0, 0, nil, [
318
+ Box.new('stbl', 0, 0, nil, [
319
+ Box.new('stts', 0, 0, {
320
+ entry_count: 1,
321
+ entries: [
322
+ {
323
+ sample_count: 10,
324
+ sample_delta: 1
325
+ }
326
+ ]
327
+ })
328
+ ])
329
+ ])
330
+ ])
331
+ ]),
332
+ Box.new('trak', 0, 0, nil, [
333
+ Box.new('hdlr', 0, 0, { handler_type: 'vide' }),
334
+ Box.new('mdia', 0, 0, nil, [
335
+ Box.new('mdhd', 0, 0, { timescale: 30 }),
336
+ Box.new('minf', 0, 0, nil, [
337
+ Box.new('stbl', 0, 0)
338
+ ])
339
+ ])
340
+ ]),
341
+ Box.new('trak', 0, 0, nil, [
342
+ Box.new('hdlr', 0, 0, { handler_type: 'vide' }),
343
+ Box.new('mdia', 0, 0, nil, [
344
+ Box.new('minf', 0, 0, nil, [
345
+ Box.new('stbl', 0, 0, nil, [
346
+ Box.new('stts', 0, 0, {
347
+ entry_count: 1,
348
+ entries: [
349
+ {
350
+ sample_count: 10,
351
+ sample_delta: 1
352
+ }
353
+ ]
354
+ })
355
+ ])
356
+ ])
357
+ ])
358
+ ]),
359
+ Box.new('trak', 0, 0, nil, [
360
+ Box.new('hdlr', 0, 0, { handler_type: 'vide' }),
361
+ Box.new('mdia', 0, 0, nil, [
362
+ Box.new('mdhd', 0, 0, { timescale: 60 }),
363
+ Box.new('minf', 0, 0, nil, [
364
+ Box.new('stbl', 0, 0, nil, [
365
+ Box.new('stts', 0, 0, {
366
+ entry_count: 2,
367
+ entries: [
368
+ {
369
+ sample_count: 10,
370
+ sample_delta: 2
371
+ },
372
+ {
373
+ sample_count: 10,
374
+ sample_delta: 1
375
+ }
376
+ ]
377
+ })
378
+ ])
379
+ ])
380
+ ])
381
+ ]),
382
+ Box.new('trak', 0, 0, nil, [
383
+ Box.new('hdlr', 0, 0, { handler_type: 'vide' }),
384
+ Box.new('mdia', 0, 0, nil, [
385
+ Box.new('mdhd', 0, 0, { timescale: 120 }),
386
+ Box.new('minf', 0, 0, nil, [
387
+ Box.new('stbl', 0, 0, nil, [
388
+ Box.new('stts', 0, 0, {
389
+ entry_count: 1,
390
+ entries: [
391
+ {
392
+ sample_count: 10,
393
+ sample_delta: 3
394
+ }
395
+ ]
396
+ })
397
+ ])
398
+ ])
399
+ ])
400
+ ]),
401
+ ])
402
+ ]
403
+ end
404
+
405
+ it 'correctly calculates frame rate' do
406
+ expect(frame_rate(box_tree)).to eq(30)
407
+ end
408
+ end
409
+
410
+ describe '.video_codecs' do
411
+ context 'when no moov box' do
412
+ let(:box_tree) { [Box.new('ftyp', 0, 16)] }
413
+
414
+ it 'returns empty array' do
415
+ expect(video_codecs(box_tree)).to eq([])
416
+ end
417
+ end
418
+
419
+ context 'when no video trak boxes' do
420
+ let(:box_tree) do
421
+ [
422
+ Box.new('moov', 0, 0, nil, [
423
+ Box.new('trak', 0, 0),
424
+ Box.new('trak', 0, 0, nil, [
425
+ Box.new('hdlr', 0, 0, { handler_type: 'soun' }),
426
+ Box.new('mdia', 0, 0, nil, [
427
+ Box.new('minf', 0, 0, nil, [
428
+ Box.new('stbl', 0, 0, nil, [
429
+ Box.new('stsd', 0, 0, nil, [
430
+ Box.new('flac', 0, 0) # Audio codec - should be ignored
431
+ ])
432
+ ])
433
+ ])
434
+ ])
435
+ ]),
436
+ Box.new('trak', 0, 0, nil, [
437
+ Box.new('hdlr', 0, 0, { component_type: 'mhlr', component_subtype: 'soun' }),
438
+ Box.new('mdia', 0, 0, nil, [
439
+ Box.new('minf', 0, 0, nil, [
440
+ Box.new('stbl', 0, 0, nil, [
441
+ Box.new('stsd', 0, 0, nil, [
442
+ Box.new('flac', 0, 0) # Audio codec - should be ignored
443
+ ])
444
+ ])
445
+ ])
446
+ ])
447
+ ])
448
+ ])
449
+ ]
450
+ end
451
+
452
+ it 'returns empty array' do
453
+ expect(video_codecs(box_tree)).to eq([])
454
+ end
455
+ end
456
+
457
+ context 'when no stsd boxes' do
458
+ let(:box_tree) do
459
+ [
460
+ Box.new('moov', 0, 0, nil, [
461
+ Box.new('trak', 0, 0, nil, [
462
+ Box.new('hdlr', 0, 0, { handler_type: 'soun' }),
463
+ Box.new('mdia', 0, 0, nil, [
464
+ Box.new('minf', 0, 0, nil, [
465
+ Box.new('stbl', 0, 0, nil, [
466
+ Box.new('stsd', 0, 0, nil, [
467
+ Box.new('flac', 0, 0) # Audio codec - should be ignored
468
+ ])
469
+ ])
470
+ ])
471
+ ])
472
+ ]),
473
+ Box.new('trak', 0, 0, nil, [
474
+ Box.new('hdlr', 0, 0, { handler_type: 'vide' })
475
+ ]),
476
+ Box.new('trak', 0, 0, nil, [
477
+ Box.new('hdlr', 0, 0, { handler_type: 'vide' }),
478
+ Box.new('mdia', 0, 0)
479
+ ]),
480
+ Box.new('trak', 0, 0, nil, [
481
+ Box.new('hdlr', 0, 0, { handler_type: 'vide' }),
482
+ Box.new('mdia', 0, 0, nil, [
483
+ Box.new('minf', 0, 0)
484
+ ])
485
+ ]),
486
+ Box.new('trak', 0, 0, nil, [
487
+ Box.new('hdlr', 0, 0, { handler_type: 'vide' }),
488
+ Box.new('mdia', 0, 0, nil, [
489
+ Box.new('minf', 0, 0, nil, [
490
+ Box.new('stbl', 0, 0)
491
+ ])
492
+ ])
493
+ ]),
494
+ Box.new('trak', 0, 0, nil, [
495
+ Box.new('hdlr', 0, 0, { component_type: 'mhlr', component_subtype: 'vide' }),
496
+ Box.new('mdia', 0, 0, nil, [
497
+ Box.new('minf', 0, 0, nil, [
498
+ Box.new('stbl', 0, 0)
499
+ ])
500
+ ])
501
+ ]),
502
+ ])
503
+ ]
504
+ end
505
+
506
+ it 'returns empty array' do
507
+ expect(video_codecs(box_tree)).to eq([])
508
+ end
509
+ end
510
+
511
+ context 'when no codecs' do
512
+ let(:box_tree) do
513
+ [
514
+ Box.new('moov', 0, 0, nil, [
515
+ Box.new('trak', 0, 0, nil, [
516
+ Box.new('hdlr', 0, 0, { handler_type: 'soun' }),
517
+ Box.new('mdia', 0, 0, nil, [
518
+ Box.new('minf', 0, 0, nil, [
519
+ Box.new('stbl', 0, 0, nil, [
520
+ Box.new('stsd', 0, 0, nil, [
521
+ Box.new('flac', 0, 0) # Audio codec - should be ignored
522
+ ])
523
+ ])
524
+ ])
525
+ ])
526
+ ]),
527
+ Box.new('trak', 0, 0, nil, [
528
+ Box.new('hdlr', 0, 0, { handler_type: 'vide' }),
529
+ Box.new('mdia', 0, 0, nil, [
530
+ Box.new('minf', 0, 0, nil, [
531
+ Box.new('stbl', 0, 0, nil, [
532
+ Box.new('stsd', 0, 0)
533
+ ])
534
+ ])
535
+ ])
536
+ ]),
537
+ Box.new('trak', 0, 0, nil, [
538
+ Box.new('hdlr', 0, 0, { component_type: 'mhlr', component_subtype: 'vide' }),
539
+ Box.new('mdia', 0, 0, nil, [
540
+ Box.new('minf', 0, 0, nil, [
541
+ Box.new('stbl', 0, 0, nil, [
542
+ Box.new('stsd', 0, 0)
543
+ ])
544
+ ])
545
+ ])
546
+ ]),
547
+ ])
548
+ ]
549
+ end
550
+
551
+ it 'returns empty array' do
552
+ expect(video_codecs(box_tree)).to eq([])
553
+ end
554
+ end
555
+
556
+ context 'when multiple codecs' do
557
+ let(:box_tree) do
558
+ [
559
+ Box.new('moov', 0, 0, nil, [
560
+ Box.new('trak', 0, 0, nil, [
561
+ Box.new('hdlr', 0, 0, { handler_type: 'soun' }),
562
+ Box.new('mdia', 0, 0, nil, [
563
+ Box.new('minf', 0, 0, nil, [
564
+ Box.new('stbl', 0, 0, nil, [
565
+ Box.new('stsd', 0, 0, nil, [
566
+ Box.new('flac', 0, 0) # Audio codec - should be ignored
567
+ ])
568
+ ])
569
+ ])
570
+ ])
571
+ ]),
572
+ Box.new('trak', 0, 0, nil, [
573
+ Box.new('hdlr', 0, 0, { handler_type: 'vide' }),
574
+ Box.new('mdia', 0, 0, nil, [
575
+ Box.new('minf', 0, 0, nil, [
576
+ Box.new('stbl', 0, 0, nil, [
577
+ Box.new('stsd', 0, 0, nil, [
578
+ Box.new('avc1', 0, 0),
579
+ Box.new('raw ', 0, 0)
580
+ ])
581
+ ])
582
+ ])
583
+ ])
584
+ ]),
585
+ Box.new('trak', 0, 0, nil, [
586
+ Box.new('hdlr', 0, 0, { component_type: 'mhlr', component_subtype: 'vide' }),
587
+ Box.new('mdia', 0, 0, nil, [
588
+ Box.new('minf', 0, 0, nil, [
589
+ Box.new('stbl', 0, 0, nil, [
590
+ Box.new('stsd', 0, 0, nil, [
591
+ Box.new('avc1', 0, 0),
592
+ ]),
593
+ Box.new('stsd', 0, 0, nil, [
594
+ Box.new('rpza', 0, 0),
595
+ ])
596
+ ])
597
+ ])
598
+ ])
599
+ ]),
600
+ Box.new('trak', 0, 0, nil, [
601
+ Box.new('hdlr', 0, 0, { handler_type: 'vide' }),
602
+ Box.new('mdia', 0, 0, nil, [
603
+ Box.new('minf', 0, 0, nil, [
604
+ Box.new('stbl', 0, 0, nil, [
605
+ Box.new('stsd', 0, 0, nil, [
606
+ Box.new('avc1', 0, 0),
607
+ ])
608
+ ])
609
+ ])
610
+ ]),
611
+ Box.new('mdia', 0, 0, nil, [
612
+ Box.new('minf', 0, 0, nil, [
613
+ Box.new('stbl', 0, 0, nil, [
614
+ Box.new('stsd', 0, 0, nil, [
615
+ Box.new('avc1', 0, 0),
616
+ Box.new('mp4v', 0, 0)
617
+ ])
618
+ ])
619
+ ])
620
+ ])
621
+ ]),
622
+ ])
623
+ ]
624
+ end
625
+
626
+ it 'returns all distinct codecs' do
627
+ expect(video_codecs(box_tree)).to match_array(['avc1', 'mp4v', 'raw ', 'rpza'])
628
+ end
629
+ end
630
+ end
631
+ end
632
+ end