bmff 0.0.1
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.
- data/.gitignore +25 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +183 -0
- data/Rakefile +9 -0
- data/bmff.gemspec +25 -0
- data/lib/bmff/binary_accessor.rb +186 -0
- data/lib/bmff/box/audio_sample_entry.rb +16 -0
- data/lib/bmff/box/base.rb +66 -0
- data/lib/bmff/box/bit_rate.rb +14 -0
- data/lib/bmff/box/chunk_large_offset.rb +16 -0
- data/lib/bmff/box/chunk_offset.rb +16 -0
- data/lib/bmff/box/clean_aperture.rb +20 -0
- data/lib/bmff/box/colour_information.rb +27 -0
- data/lib/bmff/box/compact_sample_size.rb +32 -0
- data/lib/bmff/box/composition_offset.rb +25 -0
- data/lib/bmff/box/composition_to_decode.rb +17 -0
- data/lib/bmff/box/container.rb +70 -0
- data/lib/bmff/box/copyright.rb +13 -0
- data/lib/bmff/box/data_entry_url.rb +12 -0
- data/lib/bmff/box/data_entry_urn.rb +13 -0
- data/lib/bmff/box/data_information.rb +12 -0
- data/lib/bmff/box/data_reference.rb +14 -0
- data/lib/bmff/box/degradation_priority.rb +19 -0
- data/lib/bmff/box/edit.rb +12 -0
- data/lib/bmff/box/edit_list.rb +27 -0
- data/lib/bmff/box/file_type.rb +17 -0
- data/lib/bmff/box/free_space.rb +6 -0
- data/lib/bmff/box/full.rb +11 -0
- data/lib/bmff/box/handler.rb +15 -0
- data/lib/bmff/box/hint_media_header.rb +16 -0
- data/lib/bmff/box/hint_sample_entry.rb +14 -0
- data/lib/bmff/box/level_assignment.rb +35 -0
- data/lib/bmff/box/map.rb +15 -0
- data/lib/bmff/box/media.rb +12 -0
- data/lib/bmff/box/media_data.rb +6 -0
- data/lib/bmff/box/media_header.rb +25 -0
- data/lib/bmff/box/media_information.rb +12 -0
- data/lib/bmff/box/meta_data_sample_entry.rb +5 -0
- data/lib/bmff/box/movie.rb +12 -0
- data/lib/bmff/box/movie_extends.rb +12 -0
- data/lib/bmff/box/movie_extends_header.rb +16 -0
- data/lib/bmff/box/movie_fragment.rb +12 -0
- data/lib/bmff/box/movie_fragment_header.rb +12 -0
- data/lib/bmff/box/movie_fragment_random_access.rb +12 -0
- data/lib/bmff/box/movie_fragment_random_access_offset.rb +12 -0
- data/lib/bmff/box/movie_header.rb +36 -0
- data/lib/bmff/box/null_media_header.rb +6 -0
- data/lib/bmff/box/padding_bits.rb +23 -0
- data/lib/bmff/box/pixel_aspect_ratio.rb +13 -0
- data/lib/bmff/box/progressive_download_info.rb +17 -0
- data/lib/bmff/box/sample_auxiliary_information_offsets.rb +24 -0
- data/lib/bmff/box/sample_auxiliary_information_sizes.rb +23 -0
- data/lib/bmff/box/sample_dependency_type.rb +26 -0
- data/lib/bmff/box/sample_description.rb +27 -0
- data/lib/bmff/box/sample_entry.rb +15 -0
- data/lib/bmff/box/sample_size.rb +19 -0
- data/lib/bmff/box/sample_table.rb +12 -0
- data/lib/bmff/box/sample_to_chunk.rb +20 -0
- data/lib/bmff/box/shadow_sync_sample.rb +18 -0
- data/lib/bmff/box/sound_media_header.rb +13 -0
- data/lib/bmff/box/sub_sample_information.rb +41 -0
- data/lib/bmff/box/sync_sample.rb +16 -0
- data/lib/bmff/box/text_meta_data_sample_entry.rb +18 -0
- data/lib/bmff/box/time_to_sample.rb +18 -0
- data/lib/bmff/box/track.rb +12 -0
- data/lib/bmff/box/track_extends.rb +17 -0
- data/lib/bmff/box/track_fragment.rb +12 -0
- data/lib/bmff/box/track_fragment_base_media_decode_time.rb +16 -0
- data/lib/bmff/box/track_fragment_header.rb +18 -0
- data/lib/bmff/box/track_fragment_random_access.rb +54 -0
- data/lib/bmff/box/track_group.rb +12 -0
- data/lib/bmff/box/track_group_type.rb +12 -0
- data/lib/bmff/box/track_header.rb +36 -0
- data/lib/bmff/box/track_reference.rb +12 -0
- data/lib/bmff/box/track_reference_type.rb +15 -0
- data/lib/bmff/box/track_run.rb +31 -0
- data/lib/bmff/box/track_selection.rb +16 -0
- data/lib/bmff/box/unknown.rb +5 -0
- data/lib/bmff/box/uri.rb +12 -0
- data/lib/bmff/box/uri_init.rb +15 -0
- data/lib/bmff/box/uri_meta_sample_entry.rb +24 -0
- data/lib/bmff/box/user_data.rb +12 -0
- data/lib/bmff/box/video_media_header.rb +13 -0
- data/lib/bmff/box/visual_sample_entry.rb +37 -0
- data/lib/bmff/box/xml_meta_data_sample_entry.rb +19 -0
- data/lib/bmff/box.rb +115 -0
- data/lib/bmff/file_container.rb +20 -0
- data/lib/bmff/version.rb +3 -0
- data/lib/bmff.rb +7 -0
- data/test/bmff/box/test_audio_sample_entry.rb +46 -0
- data/test/bmff/box/test_base.rb +37 -0
- data/test/bmff/box/test_bit_rate.rb +30 -0
- data/test/bmff/box/test_chunk_large_offset.rb +35 -0
- data/test/bmff/box/test_chunk_offset.rb +35 -0
- data/test/bmff/box/test_clean_aperture.rb +40 -0
- data/test/bmff/box/test_colour_information.rb +73 -0
- data/test/bmff/box/test_compact_sample_size.rb +99 -0
- data/test/bmff/box/test_composition_offset.rb +64 -0
- data/test/bmff/box/test_composition_to_decode.rb +38 -0
- data/test/bmff/box/test_copyright.rb +55 -0
- data/test/bmff/box/test_data_entry_url.rb +30 -0
- data/test/bmff/box/test_data_entry_urn.rb +32 -0
- data/test/bmff/box/test_data_information.rb +26 -0
- data/test/bmff/box/test_data_reference.rb +58 -0
- data/test/bmff/box/test_degradation_priority.rb +62 -0
- data/test/bmff/box/test_edit.rb +26 -0
- data/test/bmff/box/test_edit_list.rb +72 -0
- data/test/bmff/box/test_file_type.rb +30 -0
- data/test/bmff/box/test_free_space.rb +42 -0
- data/test/bmff/box/test_handler.rb +67 -0
- data/test/bmff/box/test_hint_media_header.rb +38 -0
- data/test/bmff/box/test_hint_sample_entry.rb +38 -0
- data/test/bmff/box/test_level_assignment.rb +50 -0
- data/test/bmff/box/test_media.rb +26 -0
- data/test/bmff/box/test_media_data.rb +25 -0
- data/test/bmff/box/test_media_header.rb +72 -0
- data/test/bmff/box/test_media_information.rb +26 -0
- data/test/bmff/box/test_movie.rb +26 -0
- data/test/bmff/box/test_movie_extends.rb +26 -0
- data/test/bmff/box/test_movie_extends_header.rb +52 -0
- data/test/bmff/box/test_movie_fragment.rb +26 -0
- data/test/bmff/box/test_movie_fragment_header.rb +30 -0
- data/test/bmff/box/test_movie_fragment_random_access.rb +26 -0
- data/test/bmff/box/test_movie_fragment_random_access_offset.rb +30 -0
- data/test/bmff/box/test_movie_header.rb +110 -0
- data/test/bmff/box/test_null_media_header.rb +28 -0
- data/test/bmff/box/test_padding_bits.rb +38 -0
- data/test/bmff/box/test_pixel_aspect_ratio.rb +28 -0
- data/test/bmff/box/test_progressive_download_info.rb +36 -0
- data/test/bmff/box/test_sample_auxiliary_information_offsets.rb +94 -0
- data/test/bmff/box/test_sample_auxiliary_information_sizes.rb +70 -0
- data/test/bmff/box/test_sample_dependency_type.rb +70 -0
- data/test/bmff/box/test_sample_description.rb +355 -0
- data/test/bmff/box/test_sample_size.rb +61 -0
- data/test/bmff/box/test_sample_table.rb +26 -0
- data/test/bmff/box/test_sample_to_chunk.rb +39 -0
- data/test/bmff/box/test_shadow_sync_sample.rb +36 -0
- data/test/bmff/box/test_sound_media_header.rb +32 -0
- data/test/bmff/box/test_sub_sample_information.rb +90 -0
- data/test/bmff/box/test_sync_sample.rb +34 -0
- data/test/bmff/box/test_text_meta_data_sample_entry.rb +49 -0
- data/test/bmff/box/test_time_to_sample.rb +36 -0
- data/test/bmff/box/test_track.rb +26 -0
- data/test/bmff/box/test_track_extends.rb +38 -0
- data/test/bmff/box/test_track_fragment.rb +26 -0
- data/test/bmff/box/test_track_fragment_base_media_decode_time.rb +52 -0
- data/test/bmff/box/test_track_fragment_header.rb +200 -0
- data/test/bmff/box/test_track_fragment_random_access.rb +96 -0
- data/test/bmff/box/test_track_group.rb +26 -0
- data/test/bmff/box/test_track_group_type.rb +30 -0
- data/test/bmff/box/test_track_header.rb +118 -0
- data/test/bmff/box/test_track_reference.rb +26 -0
- data/test/bmff/box/test_track_reference_type.rb +100 -0
- data/test/bmff/box/test_track_run.rb +282 -0
- data/test/bmff/box/test_track_selection.rb +33 -0
- data/test/bmff/box/test_uri.rb +30 -0
- data/test/bmff/box/test_uri_init.rb +32 -0
- data/test/bmff/box/test_uri_meta_sample_entry.rb +74 -0
- data/test/bmff/box/test_user_data.rb +26 -0
- data/test/bmff/box/test_video_media_header.rb +34 -0
- data/test/bmff/box/test_visual_sample_entry.rb +95 -0
- data/test/bmff/box/test_xml_meta_data_sample_entry.rb +51 -0
- data/test/bmff/test_binary_accessor.rb +805 -0
- data/test/bmff/test_file_container.rb +58 -0
- data/test/minitest_helper.rb +7 -0
- metadata +323 -0
data/.gitignore
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
*.gem
|
|
2
|
+
*.rbc
|
|
3
|
+
.bundle
|
|
4
|
+
.config
|
|
5
|
+
.yardoc
|
|
6
|
+
Gemfile.lock
|
|
7
|
+
InstalledFiles
|
|
8
|
+
_yardoc
|
|
9
|
+
coverage
|
|
10
|
+
doc/
|
|
11
|
+
lib/bundler/man
|
|
12
|
+
pkg
|
|
13
|
+
rdoc
|
|
14
|
+
spec/reports
|
|
15
|
+
test/tmp
|
|
16
|
+
test/version_tmp
|
|
17
|
+
tmp
|
|
18
|
+
.DS_Store
|
|
19
|
+
.DS_Store?
|
|
20
|
+
._*
|
|
21
|
+
.Spotlight-V100
|
|
22
|
+
.Trashes
|
|
23
|
+
Icon?
|
|
24
|
+
ehthumbs.db
|
|
25
|
+
Thumbs.db
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Copyright (c) 2014 Takayuki Ogiso
|
|
2
|
+
|
|
3
|
+
MIT License
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
a copy of this software and associated documentation files (the
|
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# bmff
|
|
2
|
+
|
|
3
|
+
This gem library is an ISO Base Media File Format (BMFF) parser.
|
|
4
|
+
You can parse BMFF file.
|
|
5
|
+
And you may be able to parse a file related to BMFF like MP4.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
Add this line to your application's Gemfile:
|
|
10
|
+
|
|
11
|
+
gem 'bmff'
|
|
12
|
+
|
|
13
|
+
And then execute:
|
|
14
|
+
|
|
15
|
+
$ bundle
|
|
16
|
+
|
|
17
|
+
Or install it yourself as:
|
|
18
|
+
|
|
19
|
+
$ gem install bmff
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
### Dump Box Structure
|
|
24
|
+
|
|
25
|
+
```ruby
|
|
26
|
+
require "bmff"
|
|
27
|
+
|
|
28
|
+
def print_box(box, level = 0)
|
|
29
|
+
puts "#{' ' * level}#{box.type} #{box.class}"
|
|
30
|
+
if box.container?
|
|
31
|
+
box.children.each do |child|
|
|
32
|
+
print_box(child, level + 1)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
open("/path/to/video.mp4", "rb:ascii-8bit") do |f|
|
|
38
|
+
file_container = BMFF::FileContainer.parse(f)
|
|
39
|
+
file_container.boxes.each do |box|
|
|
40
|
+
print_box(box)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Get Video Duration from Media Header Box
|
|
46
|
+
|
|
47
|
+
```ruby
|
|
48
|
+
require "bmff"
|
|
49
|
+
|
|
50
|
+
open("/path/to/video.mp4", "rb:ascii-8bit") do |f|
|
|
51
|
+
file_container = BMFF::FileContainer.parse(f)
|
|
52
|
+
media_header = file_container.select_descendants(BMFF::Box::MediaHeader).first
|
|
53
|
+
if media_header
|
|
54
|
+
puts media_header.duration / media_header.timescale.to_f
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Get Each Fragment Duration
|
|
60
|
+
|
|
61
|
+
```ruby
|
|
62
|
+
require "bmff"
|
|
63
|
+
|
|
64
|
+
open("/path/to/video.ismv", "rb:ascii-8bit") do |f|
|
|
65
|
+
file_container = BMFF::FileContainer.parse(f)
|
|
66
|
+
file_container.select_descendants(BMFF::Box::TrackRun).each do |track_run|
|
|
67
|
+
puts track_run.sample_duration.inject {|result, item| result + item}
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Progress
|
|
73
|
+
|
|
74
|
+
### ISO/IEC 14496-12:2012
|
|
75
|
+
|
|
76
|
+
|Box Name | Type | Status |
|
|
77
|
+
|:--------------------------------------------|:--------------:|:---------:|
|
|
78
|
+
|File Type Box | ftyp |OK | \ 4.3
|
|
79
|
+
|Media Data Box | mdat |OK | \ 8.1.1
|
|
80
|
+
|Free Space Box | free, skip |OK | \ 8.1.2
|
|
81
|
+
|Progressive Download Information Box | pdin |OK | \ 8.1.3
|
|
82
|
+
|Movie Box | moov |OK | \ 8.2.1
|
|
83
|
+
|Movie Header Box | mvhd |OK | \ 8.2.2
|
|
84
|
+
|Track Box | trak |OK | \ 8.3.1
|
|
85
|
+
|Track Header Box | tkhd |OK | \ 8.3.2
|
|
86
|
+
|Track Reference Box | tref |OK | \ 8.3.3
|
|
87
|
+
|Track Group Box | trgr |OK | \ 8.3.4
|
|
88
|
+
|Media Box | mdia |OK | \ 8.4.1
|
|
89
|
+
|Media Header Box | mdhd |OK | \ 8.4.2
|
|
90
|
+
|Handler Reference Box | hdlr |OK | \ 8.4.3
|
|
91
|
+
|Media Information Box | minf |OK | \ 8.4.4
|
|
92
|
+
|Video Media Header Box | vmhd |OK | \ 8.4.5.2
|
|
93
|
+
|Sound Media Header Box | smhd |OK | \ 8.4.5.3
|
|
94
|
+
|Hint Media Header Box | hmhd |OK | \ 8.4.5.4
|
|
95
|
+
|Null Media Header Box | nmhd |OK | \ 8.4.5.5
|
|
96
|
+
|Sample Table Box | stbl |OK | \ 8.5.1
|
|
97
|
+
|Sample Description Box | stsd |OK | \ 8.5.2
|
|
98
|
+
|Degradation Priority Box | stdp |OK | \ 8.5.3
|
|
99
|
+
|Decoding Time to Sample Box | stts |OK | \ 8.6.1.2
|
|
100
|
+
|Composition Time to Sample Box | ctts |OK | \ 8.6.1.3
|
|
101
|
+
|Composition to Decode Box | cslg |OK | \ 8.6.1.4
|
|
102
|
+
|Sync Sample Box | stss |OK | \ 8.6.2
|
|
103
|
+
|Shadow Sync Sample Box | stsh |OK | \ 8.6.3
|
|
104
|
+
|Independent and Disposable Samples Box | sdtp |OK | \ 8.6.4
|
|
105
|
+
|Edit Box | edts |OK | \ 8.6.5
|
|
106
|
+
|Edit List Box | elst |OK | \ 8.6.6
|
|
107
|
+
|Data Information Box | dinf |OK | \ 8.7.1
|
|
108
|
+
|Data Reference Box |url , urn , dref|OK | \ 8.7.2
|
|
109
|
+
|Sample Size Box | stsz |OK | \ 8.7.3.2
|
|
110
|
+
|Compact Sample Size Box | stz2 |OK | \ 8.7.3.3
|
|
111
|
+
|Sample to Chunk Box | stsc |OK | \ 8.7.4
|
|
112
|
+
|Chunk Offset Box | stco, co64 |OK | \ 8.7.5
|
|
113
|
+
|Padding Bits Box | padb |OK | \ 8.7.6
|
|
114
|
+
|Sub-Sample Information Box | subs |OK | \ 8.7.7
|
|
115
|
+
|Sample Auxiliary Information Sizes Box | saiz |OK | \ 8.7.8
|
|
116
|
+
|Sample Auxiliary Information Offsets Box | saio |OK | \ 8.7.9
|
|
117
|
+
|Movie Extends Box | mvex |OK | \ 8.8.1
|
|
118
|
+
|Movie Extends Header Box | mehd |OK | \ 8.8.2
|
|
119
|
+
|Track Extends Box | trex |OK | \ 8.8.3
|
|
120
|
+
|Movie Fragment Box | moof |OK | \ 8.8.4
|
|
121
|
+
|Movie Fragment Header Box | mfhd |OK | \ 8.8.5
|
|
122
|
+
|Track Fragment Box | traf |OK | \ 8.8.6
|
|
123
|
+
|Track Fragment Header Box | tfhd |OK | \ 8.8.7
|
|
124
|
+
|Track Fragment Run Box | trun |OK | \ 8.8.8
|
|
125
|
+
|Movie Fragment Random Access Box | mfra |OK | \ 8.8.9
|
|
126
|
+
|Track Fragment Random Access Box | tfra |OK | \ 8.8.10
|
|
127
|
+
|Movie Fragment Random Access Offset Box | mfro |OK | \ 8.8.11
|
|
128
|
+
|Track fragment decode time | tfdt |OK | \ 8.8.12
|
|
129
|
+
|Level Assignment Box | leva |OK | \ 8.8.13
|
|
130
|
+
|Sample to Group Box | sbgp |Not yet | \ 8.9.2
|
|
131
|
+
|Sample Group Description Box | sgpd |Not yet | \ 8.9.3
|
|
132
|
+
|User Data Box | udta |OK | \ 8.10.1
|
|
133
|
+
|Copyright Box | cprt |OK | \ 8.10.2
|
|
134
|
+
|Track Selection Box | tsel |OK | \ 8.10.3
|
|
135
|
+
|The Meta Box | meta |Not yet | \ 8.11.1
|
|
136
|
+
|XML Box | xml |Not yet | \ 8.11.2
|
|
137
|
+
|Binary XML Box | bxml |Not yet | \ 8.11.2
|
|
138
|
+
|The Item Location Box | iloc |Not yet | \ 8.11.3
|
|
139
|
+
|Primary Item Box | pitm |Not yet | \ 8.11.4
|
|
140
|
+
|Item Protection Box | ipro |Not yet | \ 8.11.5
|
|
141
|
+
|Item Information Box | iinf |Not yet | \ 8.11.6
|
|
142
|
+
|Additional Metadata Container Box | meco |Not yet | \ 8.11.7
|
|
143
|
+
|Metabox Relation Box | mere |Not yet | \ 8.11.8
|
|
144
|
+
|Item Data Box | idat |Not yet | \ 8.11.11
|
|
145
|
+
|Item Reference Box | iref |Not yet | \ 8.11.12
|
|
146
|
+
|Protection Scheme Information Box | sinf |Not yet | \ 8.12.1
|
|
147
|
+
|Original Format Box | frma |Not yet | \ 8.12.2
|
|
148
|
+
|Scheme Type Box | schm |Not yet | \ 8.12.5
|
|
149
|
+
|Scheme Information Box | schi |Not yet | \ 8.12.6
|
|
150
|
+
|FD Item Information Box | fiin |Not yet | \ 8.13.2
|
|
151
|
+
|File Partition Box | fpar |Not yet | \ 8.13.3
|
|
152
|
+
|FEC Reservoir Box | fecr |Not yet | \ 8.13.4
|
|
153
|
+
|FD Session Group Box | segr |Not yet | \ 8.13.5
|
|
154
|
+
|Group ID to Name Box | gitn |Not yet | \ 8.13.6
|
|
155
|
+
|File Reservoir Box | fire |Not yet | \ 8.13.7
|
|
156
|
+
|Sub Track Box | strk |Not yet | \ 8.14.3
|
|
157
|
+
|Sub Track Information Box | stri |Not yet | \ 8.14.4
|
|
158
|
+
|Sub Track Definition Box | strd |Not yet | \ 8.14.5
|
|
159
|
+
|Sub Track Sample Group Box | stsg |Not yet | \ 8.14.6
|
|
160
|
+
|Restricted Scheme Information Box | rinf |Not yet | \ 8.15.3
|
|
161
|
+
|Stereo Video Box | stvi |Not yet | \ 8.15.4.2
|
|
162
|
+
|Segment Type Box | styp |Not yet | \ 8.16.2
|
|
163
|
+
|Segment Index Box | sidx |Not yet | \ 8.16.3
|
|
164
|
+
|Subsegment Index Box | ssix |Not yet | \ 8.16.4
|
|
165
|
+
|Producer Reference Time Box | prft |Not yet | \ 8.16.5
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
## Contributing
|
|
169
|
+
|
|
170
|
+
1. Fork it ( http://github.com/zuku/bmff/fork )
|
|
171
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
172
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
173
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
|
174
|
+
5. Create new Pull Request
|
|
175
|
+
|
|
176
|
+
## License
|
|
177
|
+
|
|
178
|
+
Copyright (c) 2014 Takayuki Ogiso.
|
|
179
|
+
|
|
180
|
+
This library (except audio-visual contents) is released under the MIT license.
|
|
181
|
+
See LICENSE.txt.
|
|
182
|
+
|
|
183
|
+
The audio-visual contents are licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/4.0/.
|
data/Rakefile
ADDED
data/bmff.gemspec
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require 'bmff/version'
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |spec|
|
|
7
|
+
spec.name = "bmff"
|
|
8
|
+
spec.version = BMFF::VERSION
|
|
9
|
+
spec.authors = ["Takayuki Ogiso"]
|
|
10
|
+
spec.email = ["gomatofu@gmail.com"]
|
|
11
|
+
spec.summary = %q{ISO BMFF Parser}
|
|
12
|
+
spec.description = %q{ISO Base Media File Format file parser.}
|
|
13
|
+
spec.homepage = "https://github.com/zuku/bmff"
|
|
14
|
+
spec.license = "MIT"
|
|
15
|
+
|
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").delete_if{|x| %r|/assets/| =~ x }
|
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
19
|
+
spec.require_paths = ["lib"]
|
|
20
|
+
|
|
21
|
+
spec.required_ruby_version = '>= 1.9.0'
|
|
22
|
+
|
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.5"
|
|
24
|
+
spec.add_development_dependency "rake"
|
|
25
|
+
end
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
# vim: set expandtab tabstop=2 shiftwidth=2 softtabstop=2 autoindent:
|
|
3
|
+
|
|
4
|
+
module BMFF::BinaryAccessor
|
|
5
|
+
BYTE_ORDER = "\xFE\xFF".unpack("s").first == 0xFEFF ? :be : :le
|
|
6
|
+
|
|
7
|
+
# UTF-8, Shift_JIS or ASCII-8BIT (fallback)
|
|
8
|
+
STRING_ENCODINGS = %w(UTF-8 Shift_JIS ASCII-8BIT)
|
|
9
|
+
|
|
10
|
+
def get_int8
|
|
11
|
+
_read(1).unpack("c").first
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def write_int8(num)
|
|
15
|
+
expected_int(num, -128, 127)
|
|
16
|
+
write([num].pack("c"))
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def get_uint8
|
|
20
|
+
_read(1).unpack("C").first
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def write_uint8(num)
|
|
24
|
+
expected_int(num, 0, 255)
|
|
25
|
+
write([num].pack("C"))
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def get_int16
|
|
29
|
+
flip_byte_if_needed(_read(2)).unpack("s").first
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def write_int16(num)
|
|
33
|
+
expected_int(num, -32768, 32767)
|
|
34
|
+
write(flip_byte_if_needed([num].pack("s")))
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def get_uint16
|
|
38
|
+
_read(2).unpack("n").first
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def write_uint16(num)
|
|
42
|
+
expected_int(num, 0, 65535)
|
|
43
|
+
write([num].pack("n"))
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def get_uint24
|
|
47
|
+
(get_uint8 << 16) | get_uint16
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def write_uint24(num)
|
|
51
|
+
expected_int(num, 0, 16777215)
|
|
52
|
+
write_uint8(num >> 16)
|
|
53
|
+
write_uint16(num & 0xFFFF)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def get_int32
|
|
57
|
+
flip_byte_if_needed(_read(4)).unpack("l").first
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def write_int32(num)
|
|
61
|
+
expected_int(num, -2147483648, 2147483647)
|
|
62
|
+
write(flip_byte_if_needed([num].pack("l")))
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def get_uint32
|
|
66
|
+
_read(4).unpack("N").first
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def write_uint32(num)
|
|
70
|
+
expected_int(num, 0, 4294967295)
|
|
71
|
+
write([num].pack("N"))
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def get_int64
|
|
75
|
+
b1 = flip_byte_if_needed(_read(4)).unpack("l").first
|
|
76
|
+
b2 = _read(4).unpack("N").first
|
|
77
|
+
(b1 << 32) | b2
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def write_int64(num)
|
|
81
|
+
expected_int(num, -9223372036854775808, 9223372036854775807)
|
|
82
|
+
b1 = flip_byte_if_needed([num >> 32].pack("l"))
|
|
83
|
+
b2 = [num & 0xFFFFFFFF].pack("N")
|
|
84
|
+
write(b1 + b2)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def get_uint64
|
|
88
|
+
b1, b2 = _read(8).unpack("N2")
|
|
89
|
+
(b1 << 32) | b2
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def write_uint64(num)
|
|
93
|
+
expected_int(num, 0, 18446744073709551615)
|
|
94
|
+
write([num >> 32, num & 0xFFFFFFFF].pack("N2"))
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def get_ascii(size)
|
|
98
|
+
_read(size).unpack("a*").first
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def write_ascii(ascii)
|
|
102
|
+
raise TypeError unless ascii.kind_of?(String)
|
|
103
|
+
write([ascii].pack("a*"))
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def get_byte(size = 1)
|
|
107
|
+
_read(size)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def write_byte(byte)
|
|
111
|
+
raise TypeError unless byte.kind_of?(String)
|
|
112
|
+
write(byte)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Null-terminated string
|
|
116
|
+
# An encoding of this string is maybe UTF-8.
|
|
117
|
+
# Other encodings are possible.
|
|
118
|
+
# (e.g. Apple Media Handler outputs non UTF-8 string)
|
|
119
|
+
def get_null_terminated_string(max_byte = nil)
|
|
120
|
+
buffer = ""
|
|
121
|
+
read_byte = 0
|
|
122
|
+
until eof?
|
|
123
|
+
b = read(1)
|
|
124
|
+
read_byte += 1
|
|
125
|
+
break if b == "\x00"
|
|
126
|
+
buffer << b
|
|
127
|
+
break if max_byte && read_byte >= max_byte
|
|
128
|
+
end
|
|
129
|
+
STRING_ENCODINGS.each do |encoding|
|
|
130
|
+
buffer.force_encoding(encoding)
|
|
131
|
+
break if buffer.valid_encoding?
|
|
132
|
+
end
|
|
133
|
+
buffer
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def write_null_terminated_string(str)
|
|
137
|
+
raise TypeError unless str.kind_of?(String)
|
|
138
|
+
terminator = str.end_with?("\x00") ? "" : "\x00"
|
|
139
|
+
write(str + terminator)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Return ISO 639-2/T code
|
|
143
|
+
# Each character is compressed into 5-bit width.
|
|
144
|
+
# The bit 5 and 6 values are always 1. The bit 7 value is always 0.
|
|
145
|
+
def get_iso639_2_language
|
|
146
|
+
lang = get_uint16
|
|
147
|
+
c1 = (lang >> 10) & 0x1F | 0x60
|
|
148
|
+
c2 = (lang >> 5) & 0x1F | 0x60
|
|
149
|
+
c3 = lang & 0x1F | 0x60
|
|
150
|
+
sprintf("%c%c%c", c1, c2, c3)
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def get_uuid
|
|
154
|
+
# TODO: create and return UUID type.
|
|
155
|
+
_read(16)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
private
|
|
159
|
+
def flip_byte_if_needed(data)
|
|
160
|
+
if BYTE_ORDER == :le
|
|
161
|
+
return data.force_encoding("ascii-8bit").reverse
|
|
162
|
+
end
|
|
163
|
+
return data
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def _read(size)
|
|
167
|
+
raise TypeError unless size.kind_of?(Integer)
|
|
168
|
+
raise RangeError if size <= 0
|
|
169
|
+
data = read(size)
|
|
170
|
+
raise EOFError unless data
|
|
171
|
+
raise EOFError unless data.bytesize == size
|
|
172
|
+
data
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def expected_int(val, min, max)
|
|
176
|
+
if val.kind_of?(Integer)
|
|
177
|
+
if val >= min && val <= max
|
|
178
|
+
return true
|
|
179
|
+
else
|
|
180
|
+
raise RangeError
|
|
181
|
+
end
|
|
182
|
+
else
|
|
183
|
+
raise TypeError
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
# vim: set expandtab tabstop=2 shiftwidth=2 softtabstop=2 autoindent:
|
|
3
|
+
|
|
4
|
+
class BMFF::Box::AudioSampleEntry < BMFF::Box::SampleEntry
|
|
5
|
+
attr_accessor :reserved2, :channelcount, :samplesize, :pre_defined, :reserved3, :samplerate
|
|
6
|
+
|
|
7
|
+
def parse_data
|
|
8
|
+
super
|
|
9
|
+
@reserved2 = [io.get_uint32, io.get_uint32]
|
|
10
|
+
@channelcount = io.get_uint16
|
|
11
|
+
@samplesize = io.get_uint16
|
|
12
|
+
@pre_defined = io.get_uint16
|
|
13
|
+
@reserved3 = io.get_uint16
|
|
14
|
+
@samplerate = io.get_uint32
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
# vim: set expandtab tabstop=2 shiftwidth=2 softtabstop=2 autoindent:
|
|
3
|
+
|
|
4
|
+
class BMFF::Box::Base
|
|
5
|
+
attr_accessor :size, :type, :largesize, :usertype,
|
|
6
|
+
:io, :offset, :parent
|
|
7
|
+
|
|
8
|
+
def self.register_box(*boxtypes)
|
|
9
|
+
boxtypes.each do |boxtype|
|
|
10
|
+
BMFF::Box::Map.register_box(boxtype, self)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def actual_size
|
|
15
|
+
return largesize if size == 1
|
|
16
|
+
return nil if size == 0
|
|
17
|
+
return size
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def remaining_size
|
|
21
|
+
if actual_size
|
|
22
|
+
return (offset + actual_size) - io.pos
|
|
23
|
+
end
|
|
24
|
+
nil
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# end of box?
|
|
28
|
+
def eob?
|
|
29
|
+
if actual_size
|
|
30
|
+
return io.pos >= offset + actual_size
|
|
31
|
+
else
|
|
32
|
+
return io.eof?
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def seek_to_end
|
|
37
|
+
if actual_size
|
|
38
|
+
io.pos = offset + actual_size
|
|
39
|
+
else
|
|
40
|
+
io.seek(0, IO::SEEK_END)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def parse
|
|
45
|
+
parse_data
|
|
46
|
+
if actual_size
|
|
47
|
+
if io.pos > offset + actual_size
|
|
48
|
+
raise RangeError, "Given box size is smaller than expected."
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
seek_to_end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def parse_data
|
|
55
|
+
if size == 1
|
|
56
|
+
@largesize = io.get_uint64
|
|
57
|
+
end
|
|
58
|
+
if type == 'uuid'
|
|
59
|
+
@usertype = io.get_uuid
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def container?
|
|
64
|
+
false
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
# vim: set expandtab tabstop=2 shiftwidth=2 softtabstop=2 autoindent:
|
|
3
|
+
|
|
4
|
+
class BMFF::Box::BitRate < BMFF::Box::Base
|
|
5
|
+
attr_accessor :buffer_size_db, :max_bitrate, :avg_bitrate
|
|
6
|
+
register_box "btrt"
|
|
7
|
+
|
|
8
|
+
def parse_data
|
|
9
|
+
super
|
|
10
|
+
@buffer_size_db = io.get_uint32
|
|
11
|
+
@max_bitrate = io.get_uint32
|
|
12
|
+
@avg_bitrate = io.get_uint32
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
# vim: set expandtab tabstop=2 shiftwidth=2 softtabstop=2 autoindent:
|
|
3
|
+
|
|
4
|
+
class BMFF::Box::ChunkLargeOffset < BMFF::Box::Full
|
|
5
|
+
attr_accessor :entry_count, :chunk_offset
|
|
6
|
+
register_box "co64"
|
|
7
|
+
|
|
8
|
+
def parse_data
|
|
9
|
+
super
|
|
10
|
+
@entry_count = io.get_uint32
|
|
11
|
+
@chunk_offset = []
|
|
12
|
+
@entry_count.times do
|
|
13
|
+
@chunk_offset << io.get_uint64
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
# vim: set expandtab tabstop=2 shiftwidth=2 softtabstop=2 autoindent:
|
|
3
|
+
|
|
4
|
+
class BMFF::Box::ChunkOffset < BMFF::Box::Full
|
|
5
|
+
attr_accessor :entry_count, :chunk_offset
|
|
6
|
+
register_box "stco"
|
|
7
|
+
|
|
8
|
+
def parse_data
|
|
9
|
+
super
|
|
10
|
+
@entry_count = io.get_uint32
|
|
11
|
+
@chunk_offset = []
|
|
12
|
+
@entry_count.times do
|
|
13
|
+
@chunk_offset << io.get_uint32
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
# vim: set expandtab tabstop=2 shiftwidth=2 softtabstop=2 autoindent:
|
|
3
|
+
|
|
4
|
+
class BMFF::Box::CleanAperture < BMFF::Box::Base
|
|
5
|
+
attr_accessor :clean_aperture_width_n, :clean_aperture_width_d, :clean_aperture_height_n, :clean_aperture_height_d,
|
|
6
|
+
:horiz_off_n, :horiz_off_d, :vert_off_n, :vert_off_d
|
|
7
|
+
register_box "clap"
|
|
8
|
+
|
|
9
|
+
def parse_data
|
|
10
|
+
super
|
|
11
|
+
@clean_aperture_width_n = io.get_uint32
|
|
12
|
+
@clean_aperture_width_d = io.get_uint32
|
|
13
|
+
@clean_aperture_height_n = io.get_uint32
|
|
14
|
+
@clean_aperture_height_d = io.get_uint32
|
|
15
|
+
@horiz_off_n = io.get_uint32
|
|
16
|
+
@horiz_off_d = io.get_uint32
|
|
17
|
+
@vert_off_n = io.get_uint32
|
|
18
|
+
@vert_off_d = io.get_uint32
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
# vim: set expandtab tabstop=2 shiftwidth=2 softtabstop=2 autoindent:
|
|
3
|
+
|
|
4
|
+
class BMFF::Box::ColourInformation < BMFF::Box::Base
|
|
5
|
+
attr_accessor :colour_type,
|
|
6
|
+
:colour_primaries, :transfer_characteristics, :matrix_coefficients, :full_range_flag, :reserved1,
|
|
7
|
+
:icc_profile
|
|
8
|
+
register_box "colr"
|
|
9
|
+
|
|
10
|
+
def parse_data
|
|
11
|
+
super
|
|
12
|
+
@colour_type = io.get_ascii(4)
|
|
13
|
+
case @colour_type
|
|
14
|
+
when "nclx"
|
|
15
|
+
@colour_primaries = io.get_uint16
|
|
16
|
+
@transfer_characteristics = io.get_uint16
|
|
17
|
+
@matrix_coefficients = io.get_uint16
|
|
18
|
+
tmp = io.get_uint8
|
|
19
|
+
@full_range_flag = (tmp & 0x80) > 0
|
|
20
|
+
@reserved1 = tmp & 0x7F
|
|
21
|
+
when "rICC"
|
|
22
|
+
@icc_profile = :restricted
|
|
23
|
+
when "prof"
|
|
24
|
+
@icc_profile = :unrestricted
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
# vim: set expandtab tabstop=2 shiftwidth=2 softtabstop=2 autoindent:
|
|
3
|
+
|
|
4
|
+
class BMFF::Box::CompactSampleSize < BMFF::Box::Full
|
|
5
|
+
attr_accessor :reserved1, :field_size, :sample_count, :entry_size
|
|
6
|
+
register_box "stz2"
|
|
7
|
+
|
|
8
|
+
def parse_data
|
|
9
|
+
super
|
|
10
|
+
@reserved1 = io.get_uint24
|
|
11
|
+
@field_size = io.get_uint8
|
|
12
|
+
@sample_count = io.get_uint32
|
|
13
|
+
@entry_size = []
|
|
14
|
+
i = 0
|
|
15
|
+
while i < @sample_count
|
|
16
|
+
case @field_size
|
|
17
|
+
when 4
|
|
18
|
+
tmp = io.get_uint8
|
|
19
|
+
@entry_size << (tmp >> 4)
|
|
20
|
+
i += 1
|
|
21
|
+
@entry_size << (tmp & 0x0F) if i < @sample_count
|
|
22
|
+
when 8
|
|
23
|
+
@entry_size << io.get_uint8
|
|
24
|
+
when 16
|
|
25
|
+
@entry_size << io.get_uint16
|
|
26
|
+
else
|
|
27
|
+
raise ArgumentError, "Unsupported field_size"
|
|
28
|
+
end
|
|
29
|
+
i += 1
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|