bmff 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (167) hide show
  1. data/.gitignore +25 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +183 -0
  5. data/Rakefile +9 -0
  6. data/bmff.gemspec +25 -0
  7. data/lib/bmff/binary_accessor.rb +186 -0
  8. data/lib/bmff/box/audio_sample_entry.rb +16 -0
  9. data/lib/bmff/box/base.rb +66 -0
  10. data/lib/bmff/box/bit_rate.rb +14 -0
  11. data/lib/bmff/box/chunk_large_offset.rb +16 -0
  12. data/lib/bmff/box/chunk_offset.rb +16 -0
  13. data/lib/bmff/box/clean_aperture.rb +20 -0
  14. data/lib/bmff/box/colour_information.rb +27 -0
  15. data/lib/bmff/box/compact_sample_size.rb +32 -0
  16. data/lib/bmff/box/composition_offset.rb +25 -0
  17. data/lib/bmff/box/composition_to_decode.rb +17 -0
  18. data/lib/bmff/box/container.rb +70 -0
  19. data/lib/bmff/box/copyright.rb +13 -0
  20. data/lib/bmff/box/data_entry_url.rb +12 -0
  21. data/lib/bmff/box/data_entry_urn.rb +13 -0
  22. data/lib/bmff/box/data_information.rb +12 -0
  23. data/lib/bmff/box/data_reference.rb +14 -0
  24. data/lib/bmff/box/degradation_priority.rb +19 -0
  25. data/lib/bmff/box/edit.rb +12 -0
  26. data/lib/bmff/box/edit_list.rb +27 -0
  27. data/lib/bmff/box/file_type.rb +17 -0
  28. data/lib/bmff/box/free_space.rb +6 -0
  29. data/lib/bmff/box/full.rb +11 -0
  30. data/lib/bmff/box/handler.rb +15 -0
  31. data/lib/bmff/box/hint_media_header.rb +16 -0
  32. data/lib/bmff/box/hint_sample_entry.rb +14 -0
  33. data/lib/bmff/box/level_assignment.rb +35 -0
  34. data/lib/bmff/box/map.rb +15 -0
  35. data/lib/bmff/box/media.rb +12 -0
  36. data/lib/bmff/box/media_data.rb +6 -0
  37. data/lib/bmff/box/media_header.rb +25 -0
  38. data/lib/bmff/box/media_information.rb +12 -0
  39. data/lib/bmff/box/meta_data_sample_entry.rb +5 -0
  40. data/lib/bmff/box/movie.rb +12 -0
  41. data/lib/bmff/box/movie_extends.rb +12 -0
  42. data/lib/bmff/box/movie_extends_header.rb +16 -0
  43. data/lib/bmff/box/movie_fragment.rb +12 -0
  44. data/lib/bmff/box/movie_fragment_header.rb +12 -0
  45. data/lib/bmff/box/movie_fragment_random_access.rb +12 -0
  46. data/lib/bmff/box/movie_fragment_random_access_offset.rb +12 -0
  47. data/lib/bmff/box/movie_header.rb +36 -0
  48. data/lib/bmff/box/null_media_header.rb +6 -0
  49. data/lib/bmff/box/padding_bits.rb +23 -0
  50. data/lib/bmff/box/pixel_aspect_ratio.rb +13 -0
  51. data/lib/bmff/box/progressive_download_info.rb +17 -0
  52. data/lib/bmff/box/sample_auxiliary_information_offsets.rb +24 -0
  53. data/lib/bmff/box/sample_auxiliary_information_sizes.rb +23 -0
  54. data/lib/bmff/box/sample_dependency_type.rb +26 -0
  55. data/lib/bmff/box/sample_description.rb +27 -0
  56. data/lib/bmff/box/sample_entry.rb +15 -0
  57. data/lib/bmff/box/sample_size.rb +19 -0
  58. data/lib/bmff/box/sample_table.rb +12 -0
  59. data/lib/bmff/box/sample_to_chunk.rb +20 -0
  60. data/lib/bmff/box/shadow_sync_sample.rb +18 -0
  61. data/lib/bmff/box/sound_media_header.rb +13 -0
  62. data/lib/bmff/box/sub_sample_information.rb +41 -0
  63. data/lib/bmff/box/sync_sample.rb +16 -0
  64. data/lib/bmff/box/text_meta_data_sample_entry.rb +18 -0
  65. data/lib/bmff/box/time_to_sample.rb +18 -0
  66. data/lib/bmff/box/track.rb +12 -0
  67. data/lib/bmff/box/track_extends.rb +17 -0
  68. data/lib/bmff/box/track_fragment.rb +12 -0
  69. data/lib/bmff/box/track_fragment_base_media_decode_time.rb +16 -0
  70. data/lib/bmff/box/track_fragment_header.rb +18 -0
  71. data/lib/bmff/box/track_fragment_random_access.rb +54 -0
  72. data/lib/bmff/box/track_group.rb +12 -0
  73. data/lib/bmff/box/track_group_type.rb +12 -0
  74. data/lib/bmff/box/track_header.rb +36 -0
  75. data/lib/bmff/box/track_reference.rb +12 -0
  76. data/lib/bmff/box/track_reference_type.rb +15 -0
  77. data/lib/bmff/box/track_run.rb +31 -0
  78. data/lib/bmff/box/track_selection.rb +16 -0
  79. data/lib/bmff/box/unknown.rb +5 -0
  80. data/lib/bmff/box/uri.rb +12 -0
  81. data/lib/bmff/box/uri_init.rb +15 -0
  82. data/lib/bmff/box/uri_meta_sample_entry.rb +24 -0
  83. data/lib/bmff/box/user_data.rb +12 -0
  84. data/lib/bmff/box/video_media_header.rb +13 -0
  85. data/lib/bmff/box/visual_sample_entry.rb +37 -0
  86. data/lib/bmff/box/xml_meta_data_sample_entry.rb +19 -0
  87. data/lib/bmff/box.rb +115 -0
  88. data/lib/bmff/file_container.rb +20 -0
  89. data/lib/bmff/version.rb +3 -0
  90. data/lib/bmff.rb +7 -0
  91. data/test/bmff/box/test_audio_sample_entry.rb +46 -0
  92. data/test/bmff/box/test_base.rb +37 -0
  93. data/test/bmff/box/test_bit_rate.rb +30 -0
  94. data/test/bmff/box/test_chunk_large_offset.rb +35 -0
  95. data/test/bmff/box/test_chunk_offset.rb +35 -0
  96. data/test/bmff/box/test_clean_aperture.rb +40 -0
  97. data/test/bmff/box/test_colour_information.rb +73 -0
  98. data/test/bmff/box/test_compact_sample_size.rb +99 -0
  99. data/test/bmff/box/test_composition_offset.rb +64 -0
  100. data/test/bmff/box/test_composition_to_decode.rb +38 -0
  101. data/test/bmff/box/test_copyright.rb +55 -0
  102. data/test/bmff/box/test_data_entry_url.rb +30 -0
  103. data/test/bmff/box/test_data_entry_urn.rb +32 -0
  104. data/test/bmff/box/test_data_information.rb +26 -0
  105. data/test/bmff/box/test_data_reference.rb +58 -0
  106. data/test/bmff/box/test_degradation_priority.rb +62 -0
  107. data/test/bmff/box/test_edit.rb +26 -0
  108. data/test/bmff/box/test_edit_list.rb +72 -0
  109. data/test/bmff/box/test_file_type.rb +30 -0
  110. data/test/bmff/box/test_free_space.rb +42 -0
  111. data/test/bmff/box/test_handler.rb +67 -0
  112. data/test/bmff/box/test_hint_media_header.rb +38 -0
  113. data/test/bmff/box/test_hint_sample_entry.rb +38 -0
  114. data/test/bmff/box/test_level_assignment.rb +50 -0
  115. data/test/bmff/box/test_media.rb +26 -0
  116. data/test/bmff/box/test_media_data.rb +25 -0
  117. data/test/bmff/box/test_media_header.rb +72 -0
  118. data/test/bmff/box/test_media_information.rb +26 -0
  119. data/test/bmff/box/test_movie.rb +26 -0
  120. data/test/bmff/box/test_movie_extends.rb +26 -0
  121. data/test/bmff/box/test_movie_extends_header.rb +52 -0
  122. data/test/bmff/box/test_movie_fragment.rb +26 -0
  123. data/test/bmff/box/test_movie_fragment_header.rb +30 -0
  124. data/test/bmff/box/test_movie_fragment_random_access.rb +26 -0
  125. data/test/bmff/box/test_movie_fragment_random_access_offset.rb +30 -0
  126. data/test/bmff/box/test_movie_header.rb +110 -0
  127. data/test/bmff/box/test_null_media_header.rb +28 -0
  128. data/test/bmff/box/test_padding_bits.rb +38 -0
  129. data/test/bmff/box/test_pixel_aspect_ratio.rb +28 -0
  130. data/test/bmff/box/test_progressive_download_info.rb +36 -0
  131. data/test/bmff/box/test_sample_auxiliary_information_offsets.rb +94 -0
  132. data/test/bmff/box/test_sample_auxiliary_information_sizes.rb +70 -0
  133. data/test/bmff/box/test_sample_dependency_type.rb +70 -0
  134. data/test/bmff/box/test_sample_description.rb +355 -0
  135. data/test/bmff/box/test_sample_size.rb +61 -0
  136. data/test/bmff/box/test_sample_table.rb +26 -0
  137. data/test/bmff/box/test_sample_to_chunk.rb +39 -0
  138. data/test/bmff/box/test_shadow_sync_sample.rb +36 -0
  139. data/test/bmff/box/test_sound_media_header.rb +32 -0
  140. data/test/bmff/box/test_sub_sample_information.rb +90 -0
  141. data/test/bmff/box/test_sync_sample.rb +34 -0
  142. data/test/bmff/box/test_text_meta_data_sample_entry.rb +49 -0
  143. data/test/bmff/box/test_time_to_sample.rb +36 -0
  144. data/test/bmff/box/test_track.rb +26 -0
  145. data/test/bmff/box/test_track_extends.rb +38 -0
  146. data/test/bmff/box/test_track_fragment.rb +26 -0
  147. data/test/bmff/box/test_track_fragment_base_media_decode_time.rb +52 -0
  148. data/test/bmff/box/test_track_fragment_header.rb +200 -0
  149. data/test/bmff/box/test_track_fragment_random_access.rb +96 -0
  150. data/test/bmff/box/test_track_group.rb +26 -0
  151. data/test/bmff/box/test_track_group_type.rb +30 -0
  152. data/test/bmff/box/test_track_header.rb +118 -0
  153. data/test/bmff/box/test_track_reference.rb +26 -0
  154. data/test/bmff/box/test_track_reference_type.rb +100 -0
  155. data/test/bmff/box/test_track_run.rb +282 -0
  156. data/test/bmff/box/test_track_selection.rb +33 -0
  157. data/test/bmff/box/test_uri.rb +30 -0
  158. data/test/bmff/box/test_uri_init.rb +32 -0
  159. data/test/bmff/box/test_uri_meta_sample_entry.rb +74 -0
  160. data/test/bmff/box/test_user_data.rb +26 -0
  161. data/test/bmff/box/test_video_media_header.rb +34 -0
  162. data/test/bmff/box/test_visual_sample_entry.rb +95 -0
  163. data/test/bmff/box/test_xml_meta_data_sample_entry.rb +51 -0
  164. data/test/bmff/test_binary_accessor.rb +805 -0
  165. data/test/bmff/test_file_container.rb +58 -0
  166. data/test/minitest_helper.rb +7 -0
  167. 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
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in bmff.gemspec
4
+ gemspec
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
@@ -0,0 +1,9 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.test_files = FileList['test/**/test_*.rb']
7
+ end
8
+
9
+ task :default => :test
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