Class: FormatParser::OggParser

Inherits:
Object
  • Object
show all
Includes:
IOUtils
Defined in:
lib/parsers/ogg_parser.rb

Overview

Constant Summary collapse

MAX_POSSIBLE_PAGE_SIZE =
65307
OGG_MIME_TYPE =
'audio/ogg'

Constants included from IOUtils

IOUtils::INTEGER_DIRECTIVES

Instance Method Summary collapse

Methods included from IOUtils

#read_bytes, #read_fixed_point, #read_int, #safe_read, #safe_skip, #skip_bytes

Instance Method Details

#call(io) ⇒ Object

[View source]

13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/parsers/ogg_parser.rb', line 13

def call(io)
  # The format consists of chunks of data each called an "Ogg page". Each page
  # begins with the characters, "OggS", to identify the file as Ogg format.
  capture_pattern = safe_read(io, 4)
  return unless capture_pattern == 'OggS'

  io.seek(28) # skip not important bytes

  # Each header packet begins with the same header fields.
  #   1) packet_type: 8 bit value (the identification header is type 1)
  #   2) the characters v','o','r','b','i','s' as six octets
  packet_type, vorbis, _vorbis_version, channels, sample_rate = safe_read(io, 16).unpack('Ca6VCV')
  return unless packet_type == 1 && vorbis == 'vorbis'

  # In order to calculate the audio duration we have to read a
  # granule_position of the last Ogg page of the file. Unfortunately, we don't
  # know where the last page starts. But we do know that max size of an Ogg
  # page is 65307 bytes. So we read the last 65307 bytes from the file and try
  # to find the last page in this tail.
  pos = io.size - MAX_POSSIBLE_PAGE_SIZE
  pos = 0 if pos < 0
  io.seek(pos)
  tail = io.read(MAX_POSSIBLE_PAGE_SIZE)
  return unless tail

  granule_position = find_last_granule_position(tail)
  return unless granule_position

  duration = granule_position / sample_rate.to_f
  return if duration == Float::INFINITY

  FormatParser::Audio.new(
    format: :ogg,
    audio_sample_rate_hz: sample_rate,
    num_audio_channels: channels,
    media_duration_seconds: duration,
    content_type: OGG_MIME_TYPE,
  )
end

#likely_match?(filename) ⇒ Boolean

Returns:

  • (Boolean)
[View source]

9
10
11
# File 'lib/parsers/ogg_parser.rb', line 9

def likely_match?(filename)
  filename =~ /\.ogg$/i
end