Audible Audio: Difference between revisions
Jump to navigation
Jump to search
No edit summary |
No edit summary |
||
Line 8: | Line 8: | ||
* [http://en.wikipedia.org/wiki/Audible.com Wikipedia entry] | * [http://en.wikipedia.org/wiki/Audible.com Wikipedia entry] | ||
=== | === File format === | ||
This following Ruby code works for parsing the | The file is built up of 5 parts: | ||
* general header | |||
* text based metadata | |||
* some codec related header | |||
* offset table | |||
* data | |||
==== General header ==== | |||
First 4 bytes is the file size including these four bytes. | |||
==== Text based metadata ==== | |||
number_of_entires (32) | |||
skip (8) | |||
key_length (32) | |||
value_length (32) | |||
key (key_length) | |||
value (value_length+1) | |||
==== Offset table ==== | |||
number_of_entries (32) | |||
type (32) [0 - meta?, 1 - meta?, 2 - audio packets, 3 - meta?, 4 - meta?] | |||
offset (32) [must be relative, as the first entry in the list is always 0] | |||
==== Parsing the file ==== | |||
This following Ruby code works for parsing the known parts: | |||
video = File.new(ARGV[0]) | video = File.new(ARGV[0]) | ||
video.read( | puts "File size: #{video.read(4).unpack('N')[0].ti_i}" | ||
video.read(0xb4) # skip header | |||
sizes = video.read(4).unpack('N') | sizes = video.read(4).unpack('N') | ||
puts "Number of entires: #{sizes[0].to_i}" | puts "Number of entires: #{sizes[0].to_i}" | ||
Line 22: | Line 52: | ||
value = video.read(sizes[0].to_i+1) | value = video.read(sizes[0].to_i+1) | ||
puts "#{x} key(#{sizes[0].to_i})=#{key} value(#{sizes[0].to_i)=#{value}" | puts "#{x} key(#{sizes[0].to_i})=#{key} value(#{sizes[0].to_i)=#{value}" | ||
} | |||
video.read(0x6f) # skip | |||
sizes = video.read(4).unpack('N') | |||
puts "Number of packet table entries: #{sizes[0].to_i}" | |||
(1..sizes[0].to_i).each { | |||
sizes = video.read(8).unpack('NN') | |||
puts "type=#{sizes[0].to_i} offset=#{sizes[1].to_i}" | |||
} | } | ||
Line 33: | Line 70: | ||
Probably a seek table starts at 0x5f8: | Probably a seek table starts at 0x5f8: | ||
[[Category: Container Formats]] | [[Category: Container Formats]] |
Revision as of 17:06, 19 August 2009
- Company: Audible.com
- Samples: http://samples.mplayerhq.hu/audible/
Proprietary container format from audible.com. There is no published specification. It may contain one of five different encodings which are numbered 1 thru 5. 1-3 are rumored to be ACELP.net at varying bitrates. #4 is MP3. #5 is some unknown Sony format.
File format
The file is built up of 5 parts:
- general header
- text based metadata
- some codec related header
- offset table
- data
General header
First 4 bytes is the file size including these four bytes.
Text based metadata
number_of_entires (32) skip (8) key_length (32) value_length (32) key (key_length) value (value_length+1)
Offset table
number_of_entries (32)
type (32) [0 - meta?, 1 - meta?, 2 - audio packets, 3 - meta?, 4 - meta?] offset (32) [must be relative, as the first entry in the list is always 0]
Parsing the file
This following Ruby code works for parsing the known parts:
video = File.new(ARGV[0]) puts "File size: #{video.read(4).unpack('N')[0].ti_i}" video.read(0xb4) # skip header sizes = video.read(4).unpack('N') puts "Number of entires: #{sizes[0].to_i}" video.read(1) # skip (1..sizes[0].to_i).each { |x| sizes = video.read(8).unpack('NN') key = video.read(sizes[0].to_i) value = video.read(sizes[0].to_i+1) puts "#{x} key(#{sizes[0].to_i})=#{key} value(#{sizes[0].to_i)=#{value}" } video.read(0x6f) # skip sizes = video.read(4).unpack('N') puts "Number of packet table entries: #{sizes[0].to_i}" (1..sizes[0].to_i).each { sizes = video.read(8).unpack('NN') puts "type=#{sizes[0].to_i} offset=#{sizes[1].to_i}" }
Sample output (stripped):
13 key(5)=codec value(7)=acelp85 16 key(10)=HeaderSeed value(10)=1158166611 18 key(9)=HeaderKey value(43)=3759801365 1641076194 2988088058 4282540117 19 key(15)=EncryptedBlocks value(5)=39333
Probably a seek table starts at 0x5f8: