ruby-ogginfo 0.3.2 → 0.4
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/History.txt +6 -0
- data/lib/ogginfo.rb +146 -46
- data/test/test_ruby-ogginfo.rb +1 -1
- metadata +10 -5
data/History.txt
CHANGED
data/lib/ogginfo.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
|
-
# $Id: ogginfo.rb 39 2008-03-15 17:21:31Z moumar $
|
2
|
-
#
|
3
1
|
# see http://www.xiph.org/ogg/vorbis/docs.html for documentation on vorbis format
|
4
|
-
# http://www.xiph.org/
|
2
|
+
# http://www.xiph.org/vorbis/doc/v-comment.html
|
3
|
+
# http://www.xiph.org/vorbis/doc/framing.html
|
5
4
|
#
|
6
5
|
# License: ruby
|
7
6
|
|
@@ -24,25 +23,91 @@ end
|
|
24
23
|
class OggInfoError < StandardError ; end
|
25
24
|
|
26
25
|
class OggInfo
|
27
|
-
VERSION = "0.
|
26
|
+
VERSION = "0.4"
|
27
|
+
CHECKSUM_TABLE = [
|
28
|
+
0x00000000,0x04c11db7,0x09823b6e,0x0d4326d9,
|
29
|
+
0x130476dc,0x17c56b6b,0x1a864db2,0x1e475005,
|
30
|
+
0x2608edb8,0x22c9f00f,0x2f8ad6d6,0x2b4bcb61,
|
31
|
+
0x350c9b64,0x31cd86d3,0x3c8ea00a,0x384fbdbd,
|
32
|
+
0x4c11db70,0x48d0c6c7,0x4593e01e,0x4152fda9,
|
33
|
+
0x5f15adac,0x5bd4b01b,0x569796c2,0x52568b75,
|
34
|
+
0x6a1936c8,0x6ed82b7f,0x639b0da6,0x675a1011,
|
35
|
+
0x791d4014,0x7ddc5da3,0x709f7b7a,0x745e66cd,
|
36
|
+
0x9823b6e0,0x9ce2ab57,0x91a18d8e,0x95609039,
|
37
|
+
0x8b27c03c,0x8fe6dd8b,0x82a5fb52,0x8664e6e5,
|
38
|
+
0xbe2b5b58,0xbaea46ef,0xb7a96036,0xb3687d81,
|
39
|
+
0xad2f2d84,0xa9ee3033,0xa4ad16ea,0xa06c0b5d,
|
40
|
+
0xd4326d90,0xd0f37027,0xddb056fe,0xd9714b49,
|
41
|
+
0xc7361b4c,0xc3f706fb,0xceb42022,0xca753d95,
|
42
|
+
0xf23a8028,0xf6fb9d9f,0xfbb8bb46,0xff79a6f1,
|
43
|
+
0xe13ef6f4,0xe5ffeb43,0xe8bccd9a,0xec7dd02d,
|
44
|
+
0x34867077,0x30476dc0,0x3d044b19,0x39c556ae,
|
45
|
+
0x278206ab,0x23431b1c,0x2e003dc5,0x2ac12072,
|
46
|
+
0x128e9dcf,0x164f8078,0x1b0ca6a1,0x1fcdbb16,
|
47
|
+
0x018aeb13,0x054bf6a4,0x0808d07d,0x0cc9cdca,
|
48
|
+
0x7897ab07,0x7c56b6b0,0x71159069,0x75d48dde,
|
49
|
+
0x6b93dddb,0x6f52c06c,0x6211e6b5,0x66d0fb02,
|
50
|
+
0x5e9f46bf,0x5a5e5b08,0x571d7dd1,0x53dc6066,
|
51
|
+
0x4d9b3063,0x495a2dd4,0x44190b0d,0x40d816ba,
|
52
|
+
0xaca5c697,0xa864db20,0xa527fdf9,0xa1e6e04e,
|
53
|
+
0xbfa1b04b,0xbb60adfc,0xb6238b25,0xb2e29692,
|
54
|
+
0x8aad2b2f,0x8e6c3698,0x832f1041,0x87ee0df6,
|
55
|
+
0x99a95df3,0x9d684044,0x902b669d,0x94ea7b2a,
|
56
|
+
0xe0b41de7,0xe4750050,0xe9362689,0xedf73b3e,
|
57
|
+
0xf3b06b3b,0xf771768c,0xfa325055,0xfef34de2,
|
58
|
+
0xc6bcf05f,0xc27dede8,0xcf3ecb31,0xcbffd686,
|
59
|
+
0xd5b88683,0xd1799b34,0xdc3abded,0xd8fba05a,
|
60
|
+
0x690ce0ee,0x6dcdfd59,0x608edb80,0x644fc637,
|
61
|
+
0x7a089632,0x7ec98b85,0x738aad5c,0x774bb0eb,
|
62
|
+
0x4f040d56,0x4bc510e1,0x46863638,0x42472b8f,
|
63
|
+
0x5c007b8a,0x58c1663d,0x558240e4,0x51435d53,
|
64
|
+
0x251d3b9e,0x21dc2629,0x2c9f00f0,0x285e1d47,
|
65
|
+
0x36194d42,0x32d850f5,0x3f9b762c,0x3b5a6b9b,
|
66
|
+
0x0315d626,0x07d4cb91,0x0a97ed48,0x0e56f0ff,
|
67
|
+
0x1011a0fa,0x14d0bd4d,0x19939b94,0x1d528623,
|
68
|
+
0xf12f560e,0xf5ee4bb9,0xf8ad6d60,0xfc6c70d7,
|
69
|
+
0xe22b20d2,0xe6ea3d65,0xeba91bbc,0xef68060b,
|
70
|
+
0xd727bbb6,0xd3e6a601,0xdea580d8,0xda649d6f,
|
71
|
+
0xc423cd6a,0xc0e2d0dd,0xcda1f604,0xc960ebb3,
|
72
|
+
0xbd3e8d7e,0xb9ff90c9,0xb4bcb610,0xb07daba7,
|
73
|
+
0xae3afba2,0xaafbe615,0xa7b8c0cc,0xa379dd7b,
|
74
|
+
0x9b3660c6,0x9ff77d71,0x92b45ba8,0x9675461f,
|
75
|
+
0x8832161a,0x8cf30bad,0x81b02d74,0x857130c3,
|
76
|
+
0x5d8a9099,0x594b8d2e,0x5408abf7,0x50c9b640,
|
77
|
+
0x4e8ee645,0x4a4ffbf2,0x470cdd2b,0x43cdc09c,
|
78
|
+
0x7b827d21,0x7f436096,0x7200464f,0x76c15bf8,
|
79
|
+
0x68860bfd,0x6c47164a,0x61043093,0x65c52d24,
|
80
|
+
0x119b4be9,0x155a565e,0x18197087,0x1cd86d30,
|
81
|
+
0x029f3d35,0x065e2082,0x0b1d065b,0x0fdc1bec,
|
82
|
+
0x3793a651,0x3352bbe6,0x3e119d3f,0x3ad08088,
|
83
|
+
0x2497d08d,0x2056cd3a,0x2d15ebe3,0x29d4f654,
|
84
|
+
0xc5a92679,0xc1683bce,0xcc2b1d17,0xc8ea00a0,
|
85
|
+
0xd6ad50a5,0xd26c4d12,0xdf2f6bcb,0xdbee767c,
|
86
|
+
0xe3a1cbc1,0xe760d676,0xea23f0af,0xeee2ed18,
|
87
|
+
0xf0a5bd1d,0xf464a0aa,0xf9278673,0xfde69bc4,
|
88
|
+
0x89b8fd09,0x8d79e0be,0x803ac667,0x84fbdbd0,
|
89
|
+
0x9abc8bd5,0x9e7d9662,0x933eb0bb,0x97ffad0c,
|
90
|
+
0xafb010b1,0xab710d06,0xa6322bdf,0xa2f33668,
|
91
|
+
0xbcb4666d,0xb8757bda,0xb5365d03,0xb1f740b4
|
92
|
+
]
|
93
|
+
|
28
94
|
attr_reader :channels, :samplerate, :bitrate, :nominal_bitrate, :length
|
29
95
|
|
30
96
|
# +tag+ is a hash containing the vorbis tag like "Artist", "Title", and the like
|
31
97
|
attr_reader :tag
|
32
98
|
|
33
99
|
# create new instance of OggInfo, using +charset+ to convert tags to
|
34
|
-
def initialize(filename, charset = "
|
100
|
+
def initialize(filename, charset = "utf-8")
|
35
101
|
@filename = filename
|
36
102
|
@charset = charset
|
37
103
|
@file = File.new(@filename, "rb")
|
38
104
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
extract_tag
|
105
|
+
frames = (1..2).collect { |i| OggInfo.read_frame(@file) }
|
106
|
+
extract_vorbis_infos(frames[0])
|
107
|
+
extract_tag(frames[1])
|
43
108
|
convert_tag_charset("utf-8", @charset)
|
44
|
-
@
|
45
|
-
|
109
|
+
@original_tag = @tag.dup
|
110
|
+
@length = get_length
|
46
111
|
@bitrate = @file.stat.size.to_f*8/@length
|
47
112
|
@file.close
|
48
113
|
end
|
@@ -63,9 +128,9 @@ class OggInfo
|
|
63
128
|
ret
|
64
129
|
end
|
65
130
|
|
66
|
-
#
|
131
|
+
# commits any tags to file
|
67
132
|
def close
|
68
|
-
if @tag != @
|
133
|
+
if @tag != @original_tag
|
69
134
|
cmd = %w{vorbiscomment -w}
|
70
135
|
convert_tag_charset(@charset, "utf-8")
|
71
136
|
|
@@ -86,63 +151,98 @@ class OggInfo
|
|
86
151
|
"channels #{@channels} samplerate #{@samplerate} bitrate #{@nominal_bitrate} bitrate #{@bitrate} length #{@length} #{@tag.inspect}"
|
87
152
|
end
|
88
153
|
|
89
|
-
|
90
|
-
def
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
154
|
+
# read an ogg frame from the +file+
|
155
|
+
def self.read_frame(file)
|
156
|
+
frame = {}
|
157
|
+
|
158
|
+
frame[:file_position] = file.pos
|
159
|
+
|
160
|
+
return nil if file.eof?
|
161
|
+
chunk = file.read(27)
|
162
|
+
|
163
|
+
capture_pattern,
|
164
|
+
frame[:version],
|
165
|
+
frame[:header_type],
|
166
|
+
frame[:granule_pos],
|
167
|
+
frame[:bitstream_serial_number],
|
168
|
+
frame[:page_sequence_number],
|
169
|
+
frame[:checksum],
|
170
|
+
frame[:page_segments] = chunk.unpack("a4CCQNNNC")
|
171
|
+
|
172
|
+
if capture_pattern != "OggS"
|
173
|
+
raise(OggInfoError, "bad magic number '#{capture_pattern}'")
|
174
|
+
end
|
175
|
+
|
176
|
+
segment_sizes = file.read(frame[:page_segments]).unpack("C*")
|
177
|
+
frame[:header_size] = 27 + frame[:page_segments]
|
178
|
+
frame[:body_size] = segment_sizes.inject(0) { |sum, i| sum += i }
|
179
|
+
frame[:size] = frame[:header_size] + frame[:body_size]
|
180
|
+
file.seek(frame[:body_size], IO::SEEK_CUR)
|
181
|
+
frame
|
182
|
+
end
|
183
|
+
|
184
|
+
# compute the checksum of a given +frame+ from a given +file+, you can compare it with frame[:checksum].
|
185
|
+
def self.checksum(file, frame)
|
186
|
+
original_pos = file.pos
|
187
|
+
file.seek(frame[:file_position])
|
188
|
+
data = file.read(frame[:size])
|
189
|
+
data[22] = data[23] = data[24] = data[25] = 0
|
190
|
+
|
191
|
+
crc = 0
|
192
|
+
data.each_byte do |byte|
|
193
|
+
crc = (crc << 8)^CHECKSUM_TABLE[((crc >> 24)&0xff) ^ byte]
|
194
|
+
crc = crc & 0xffffffff
|
102
195
|
end
|
196
|
+
|
197
|
+
# "reverse" it
|
198
|
+
crc = [crc].pack("V").unpack("N").first
|
199
|
+
file.seek(original_pos)
|
200
|
+
crc
|
103
201
|
end
|
104
202
|
|
105
|
-
|
106
|
-
|
107
|
-
@
|
203
|
+
private
|
204
|
+
def extract_vorbis_infos(frame)
|
205
|
+
@file.seek(frame[:file_position] + frame[:header_size] + 1 ) # seek after "vorbis"
|
206
|
+
vorbis_string, vorbis_version, @channels, @samplerate, upper_bitrate, @nominal_bitrate, lower_bitrate = @file.read(27).unpack("a6VCV4")
|
108
207
|
if @nominal_bitrate == 0
|
109
|
-
if
|
208
|
+
if upper_bitrate == 2**32 - 1 or lower_bitrate == 2**32 - 1
|
110
209
|
@nominal_bitrate = 0
|
111
210
|
else
|
112
|
-
@nominal_bitrate = (
|
211
|
+
@nominal_bitrate = (upper_bitrate + lower_bitrate)/2
|
113
212
|
end
|
114
213
|
end
|
115
214
|
end
|
116
215
|
|
117
|
-
def extract_tag
|
216
|
+
def extract_tag(frame)
|
217
|
+
@file.seek(frame[:file_position] + frame[:header_size] + 1 + "vorbis".size)
|
218
|
+
vendor_length = @file.read(4).unpack("V").first
|
219
|
+
@vendor = @file.read(vendor_length)
|
220
|
+
|
118
221
|
@tag = {}
|
119
|
-
@file.seek(22, IO::SEEK_CUR)
|
120
|
-
segs = @file.read(1).unpack("C")[0]
|
121
|
-
@file.seek(segs + 7, IO::SEEK_CUR)
|
122
|
-
size = @file.read(4).unpack("V")[0]
|
123
|
-
@file.seek(size, IO::SEEK_CUR)
|
124
222
|
tag_size = @file.read(4).unpack("V")[0]
|
125
223
|
|
126
224
|
tag_size.times do |i|
|
127
225
|
size = @file.read(4).unpack("V")[0]
|
128
226
|
comment = @file.read(size)
|
129
|
-
key, val = comment.split(
|
227
|
+
key, val = comment.split(/=/, 2)
|
130
228
|
@tag[key.downcase] = val
|
131
229
|
end
|
132
230
|
end
|
133
231
|
|
134
|
-
def
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
232
|
+
def get_length
|
233
|
+
@file.seek(0)
|
234
|
+
last_frame = nil
|
235
|
+
begin
|
236
|
+
while f = OggInfo.read_frame(@file)
|
237
|
+
last_frame = f
|
238
|
+
end
|
239
|
+
rescue OggInfoError
|
142
240
|
end
|
241
|
+
last_frame[:granule_pos].to_f / @samplerate
|
143
242
|
end
|
144
243
|
|
145
244
|
def convert_tag_charset(from_charset, to_charset)
|
245
|
+
return if from_charset == to_charset
|
146
246
|
Iconv.open(to_charset, from_charset) do |ic|
|
147
247
|
@tag.each do |k, v|
|
148
248
|
@tag[k] = ic.iconv(v)
|
data/test/test_ruby-ogginfo.rb
CHANGED
@@ -117,7 +117,7 @@ class OggInfoTest < Test::Unit::TestCase
|
|
117
117
|
assert_equal 64000, ogg.nominal_bitrate
|
118
118
|
assert_equal 2, ogg.channels
|
119
119
|
assert_equal 44100, ogg.samplerate
|
120
|
-
|
120
|
+
assert_in_delta(0.5, ogg.length, 1)
|
121
121
|
#average_bitrate
|
122
122
|
end
|
123
123
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-ogginfo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: "0.4"
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Guillaume Pierronnet
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-12-04 00:00:00 +01:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -22,7 +22,10 @@ dependencies:
|
|
22
22
|
- !ruby/object:Gem::Version
|
23
23
|
version: 1.9.0
|
24
24
|
version:
|
25
|
-
description:
|
25
|
+
description: |-
|
26
|
+
ruby-ogginfo gives you access to low level information on ogg files
|
27
|
+
(bitrate, length, samplerate, encoder, etc... ), as well as tag.
|
28
|
+
It is written in pure ruby.
|
26
29
|
email: moumar@rubyforge.org
|
27
30
|
executables: []
|
28
31
|
|
@@ -42,6 +45,8 @@ files:
|
|
42
45
|
- test/test_ruby-ogginfo.rb
|
43
46
|
has_rdoc: true
|
44
47
|
homepage: http://ruby-ogginfo.rubyforge.org/
|
48
|
+
licenses: []
|
49
|
+
|
45
50
|
post_install_message:
|
46
51
|
rdoc_options:
|
47
52
|
- --main
|
@@ -63,9 +68,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
63
68
|
requirements: []
|
64
69
|
|
65
70
|
rubyforge_project: ruby-ogginfo
|
66
|
-
rubygems_version: 1.3.
|
71
|
+
rubygems_version: 1.3.5
|
67
72
|
signing_key:
|
68
|
-
specification_version:
|
73
|
+
specification_version: 3
|
69
74
|
summary: ruby-ogginfo is a pure-ruby library that gives low level informations on ogg files
|
70
75
|
test_files:
|
71
76
|
- test/test_ruby-ogginfo.rb
|