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