ruby-ogginfo 0.4.2 → 0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +4 -0
- data/Manifest.txt +1 -1
- data/{README.txt → README.rdoc} +1 -0
- data/Rakefile +6 -2
- data/lib/ogginfo.rb +31 -6
- data/test/test_ruby-spxinfo.rb +105 -0
- metadata +43 -16
data/History.txt
CHANGED
data/Manifest.txt
CHANGED
data/{README.txt → README.rdoc}
RENAMED
data/Rakefile
CHANGED
@@ -2,6 +2,9 @@
|
|
2
2
|
|
3
3
|
require 'rubygems'
|
4
4
|
require 'hoe'
|
5
|
+
|
6
|
+
Hoe.plugin :yard
|
7
|
+
|
5
8
|
require 'lib/ogginfo.rb'
|
6
9
|
|
7
10
|
Hoe.new('ruby-ogginfo', OggInfo::VERSION) do |p|
|
@@ -9,10 +12,11 @@ Hoe.new('ruby-ogginfo', OggInfo::VERSION) do |p|
|
|
9
12
|
p.author = 'Guillaume Pierronnet'
|
10
13
|
p.email = 'moumar@rubyforge.org'
|
11
14
|
p.summary = 'ruby-ogginfo is a pure-ruby library that gives low level informations on ogg files'
|
12
|
-
p.description = p.paragraphs_of('README.
|
13
|
-
p.url = p.paragraphs_of('README.
|
15
|
+
p.description = p.paragraphs_of('README.rdoc', 3).first
|
16
|
+
p.url = p.paragraphs_of('README.rdoc', 1).first
|
14
17
|
p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
|
15
18
|
p.remote_rdoc_dir = ''
|
19
|
+
p.rdoc_locations << "rubyforge.org:/var/www/gforge-projects/ruby-ogginfo/"
|
16
20
|
end
|
17
21
|
|
18
22
|
# vim: syntax=Ruby
|
data/lib/ogginfo.rb
CHANGED
@@ -23,7 +23,7 @@ end
|
|
23
23
|
class OggInfoError < StandardError ; end
|
24
24
|
|
25
25
|
class OggInfo
|
26
|
-
VERSION = "0.
|
26
|
+
VERSION = "0.5"
|
27
27
|
CHECKSUM_TABLE = [
|
28
28
|
0x00000000,0x04c11db7,0x09823b6e,0x0d4326d9,
|
29
29
|
0x130476dc,0x17c56b6b,0x1a864db2,0x1e475005,
|
@@ -103,7 +103,7 @@ class OggInfo
|
|
103
103
|
@file = File.new(@filename, "rb")
|
104
104
|
|
105
105
|
frames = (1..2).collect { |i| OggInfo.read_frame(@file) }
|
106
|
-
|
106
|
+
extract_bitstream_infos(frames[0])
|
107
107
|
extract_tag(frames[1])
|
108
108
|
convert_tag_charset("utf-8", @charset)
|
109
109
|
@original_tag = @tag.dup
|
@@ -130,7 +130,7 @@ class OggInfo
|
|
130
130
|
|
131
131
|
# commits any tags to file
|
132
132
|
def close
|
133
|
-
if @tag != @original_tag
|
133
|
+
if @bitstream_format == "vorbis" && @tag != @original_tag
|
134
134
|
cmd = %w{vorbiscomment -w}
|
135
135
|
convert_tag_charset(@charset, "utf-8")
|
136
136
|
|
@@ -202,20 +202,45 @@ class OggInfo
|
|
202
202
|
end
|
203
203
|
|
204
204
|
private
|
205
|
+
def extract_bitstream_infos(frame)
|
206
|
+
@file.seek(frame[:file_position] + frame[:header_size] + 1)
|
207
|
+
@bitstream_format = @file.read(6).rstrip()
|
208
|
+
case @bitstream_format
|
209
|
+
when "vorbis" : extract_vorbis_infos(frame)
|
210
|
+
when "peex" :
|
211
|
+
#Speex does not align itself to a 4 byte boundary.
|
212
|
+
@bitstream_format="Speex"
|
213
|
+
extract_speex_infos(frame)
|
214
|
+
else raise(OggInfoError,"Unknown bitstream format #{@bitstream_format}")
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def extract_speex_infos(frame)
|
219
|
+
@file.seek(frame[:file_position] + frame[:header_size] )
|
220
|
+
speex_string,speex_version,speex_version_id,header_size,@samplerate,mode,mode_bitstream_version,
|
221
|
+
@channels,bitrate,framesize,vbr = @file.read(28+ 9 * 4).unpack("A8A20VVVVVVVVV")
|
222
|
+
#not sure how to make sense of the bitrate info,picard doesn't show it either...
|
223
|
+
end
|
224
|
+
|
205
225
|
def extract_vorbis_infos(frame)
|
206
|
-
@file.seek(frame[:file_position] + frame[:header_size] + 1 )
|
226
|
+
@file.seek(frame[:file_position] + frame[:header_size] + 1 )
|
227
|
+
|
207
228
|
vorbis_string, vorbis_version, @channels, @samplerate, upper_bitrate, @nominal_bitrate, lower_bitrate = @file.read(27).unpack("a6VCV4")
|
208
229
|
if @nominal_bitrate == 0
|
209
230
|
if upper_bitrate == 2**32 - 1 or lower_bitrate == 2**32 - 1
|
210
231
|
@nominal_bitrate = 0
|
211
232
|
else
|
212
233
|
@nominal_bitrate = (upper_bitrate + lower_bitrate)/2
|
213
|
-
end
|
234
|
+
end
|
214
235
|
end
|
215
236
|
end
|
216
237
|
|
217
238
|
def extract_tag(frame)
|
218
|
-
@file.seek(frame[:file_position] + frame[:header_size]
|
239
|
+
@file.seek(frame[:file_position] + frame[:header_size] )
|
240
|
+
# GG: Vorbis includes a preamble "vorbis", which is not included in the comments,
|
241
|
+
# but is definitely in the /libvorbis/lib/info.c _vorbis_pack_comment reference implementation.
|
242
|
+
# Speex does not seem to include this preamble.
|
243
|
+
@file.read(7) if @bitstream_format=="vorbis"
|
219
244
|
vendor_length = @file.read(4).unpack("V").first
|
220
245
|
@vendor = @file.read(vendor_length)
|
221
246
|
|
@@ -0,0 +1,105 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
|
3
|
+
$:.unshift("lib/")
|
4
|
+
|
5
|
+
require "test/unit"
|
6
|
+
require "ogginfo"
|
7
|
+
require "fileutils"
|
8
|
+
require "tempfile"
|
9
|
+
|
10
|
+
VALID_SPX = <<EOF
|
11
|
+
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
|
55
|
+
uTv3X00=
|
56
|
+
EOF
|
57
|
+
|
58
|
+
class SpxInfoTest < Test::Unit::TestCase
|
59
|
+
|
60
|
+
TEMP_FILE = File.join(Dir.tmpdir, "test.spxinfo.spx")
|
61
|
+
|
62
|
+
def setup
|
63
|
+
valid_spx_file = VALID_SPX.unpack("m*").first
|
64
|
+
File.open(TEMP_FILE, "w") { |f| f.write(valid_spx_file) }
|
65
|
+
end
|
66
|
+
|
67
|
+
def teardown
|
68
|
+
FileUtils.rm_f(TEMP_FILE)
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_infos
|
72
|
+
OggInfo.open(TEMP_FILE) do |spx|
|
73
|
+
assert_equal 1, spx.channels
|
74
|
+
assert_equal 32000, spx.samplerate
|
75
|
+
assert_in_delta(0.5, spx.length, 1)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_generated_info
|
80
|
+
generate_spx
|
81
|
+
OggInfo.open("test.spx") do |spx|
|
82
|
+
assert_equal 2, spx.channels
|
83
|
+
assert_equal 44100, spx.samplerate
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
|
88
|
+
def test_charset
|
89
|
+
generate_spx
|
90
|
+
OggInfo.open("test.spx", "utf-8") do |spx|
|
91
|
+
assert_equal "spxinfotest", spx.tag["author"]
|
92
|
+
end
|
93
|
+
|
94
|
+
OggInfo.open("test.spx", "iso-8859-1") do |spx|
|
95
|
+
assert_equal "hello\xe9", spx.tag["test"]
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def generate_spx
|
100
|
+
unless test(?f, "test.spx")
|
101
|
+
system("dd if=/dev/urandom bs=1024 count=3000 | speexenc --rate 44100 --stereo --author spxinfotest --title SpxInfoTest --comment test=\"hello\303\251\" - test.spx") or
|
102
|
+
flunk("cannot generate \"test.spx\", tests cannot be fully performed")
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,11 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-ogginfo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 5
|
8
|
+
version: "0.5"
|
5
9
|
platform: ruby
|
6
10
|
authors:
|
7
11
|
- Guillaume Pierronnet
|
@@ -9,19 +13,37 @@ autorequire:
|
|
9
13
|
bindir: bin
|
10
14
|
cert_chain: []
|
11
15
|
|
12
|
-
date:
|
16
|
+
date: 2011-01-13 00:00:00 +01:00
|
13
17
|
default_executable:
|
14
18
|
dependencies:
|
15
19
|
- !ruby/object:Gem::Dependency
|
16
|
-
name: hoe
|
20
|
+
name: hoe-yard
|
21
|
+
prerelease: false
|
22
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
segments:
|
27
|
+
- 0
|
28
|
+
- 1
|
29
|
+
- 2
|
30
|
+
version: 0.1.2
|
17
31
|
type: :development
|
18
|
-
|
19
|
-
|
32
|
+
version_requirements: *id001
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: hoe
|
35
|
+
prerelease: false
|
36
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
20
37
|
requirements:
|
21
38
|
- - ">="
|
22
39
|
- !ruby/object:Gem::Version
|
23
|
-
|
24
|
-
|
40
|
+
segments:
|
41
|
+
- 2
|
42
|
+
- 8
|
43
|
+
- 0
|
44
|
+
version: 2.8.0
|
45
|
+
type: :development
|
46
|
+
version_requirements: *id002
|
25
47
|
description: |-
|
26
48
|
ruby-ogginfo gives you access to low level information on ogg files
|
27
49
|
(bitrate, length, samplerate, encoder, etc... ), as well as tag.
|
@@ -34,43 +56,48 @@ extensions: []
|
|
34
56
|
extra_rdoc_files:
|
35
57
|
- History.txt
|
36
58
|
- Manifest.txt
|
37
|
-
- README.txt
|
38
59
|
files:
|
39
60
|
- History.txt
|
40
61
|
- Manifest.txt
|
41
|
-
- README.
|
62
|
+
- README.rdoc
|
42
63
|
- Rakefile
|
43
64
|
- setup.rb
|
44
65
|
- lib/ogginfo.rb
|
45
66
|
- test/test_ruby-ogginfo.rb
|
46
|
-
has_rdoc:
|
47
|
-
homepage:
|
67
|
+
has_rdoc: yard
|
68
|
+
homepage: |
|
69
|
+
http://ruby-ogginfo.rubyforge.org/
|
70
|
+
|
48
71
|
licenses: []
|
49
72
|
|
50
73
|
post_install_message:
|
51
74
|
rdoc_options:
|
52
|
-
- --
|
53
|
-
-
|
75
|
+
- --title
|
76
|
+
- RubyOgginfo Documentation
|
77
|
+
- --quiet
|
54
78
|
require_paths:
|
55
79
|
- lib
|
56
80
|
required_ruby_version: !ruby/object:Gem::Requirement
|
57
81
|
requirements:
|
58
82
|
- - ">="
|
59
83
|
- !ruby/object:Gem::Version
|
84
|
+
segments:
|
85
|
+
- 0
|
60
86
|
version: "0"
|
61
|
-
version:
|
62
87
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
63
88
|
requirements:
|
64
89
|
- - ">="
|
65
90
|
- !ruby/object:Gem::Version
|
91
|
+
segments:
|
92
|
+
- 0
|
66
93
|
version: "0"
|
67
|
-
version:
|
68
94
|
requirements: []
|
69
95
|
|
70
96
|
rubyforge_project: ruby-ogginfo
|
71
|
-
rubygems_version: 1.3.
|
97
|
+
rubygems_version: 1.3.6
|
72
98
|
signing_key:
|
73
99
|
specification_version: 3
|
74
100
|
summary: ruby-ogginfo is a pure-ruby library that gives low level informations on ogg files
|
75
101
|
test_files:
|
76
102
|
- test/test_ruby-ogginfo.rb
|
103
|
+
- test/test_ruby-spxinfo.rb
|