Class: Subconv::Scc::Reader

Inherits:
Object
  • Object
show all
Defined in:
lib/subconv/scc/reader.rb

Overview

SCC reader Parse and render an SCC file sequentially into a background and foreground grid like a TV set would do and store the resulting closed captions as grid snapshots into an array whenever the foreground grid changes.

Only captions in data channel 1 are read. Also, invalid byte parity will raise an error unless checking is disabled. The advanced recovery methods mentioned in CEA608 are not implemented since the source is assumed to contain no errors (e.g. DVD source).

Defined Under Namespace

Classes: Error, InvalidFormatError, ParityError, State

Constant Summary collapse

LINE_REGEXP =

Regular expression for parsing one line of data

/^(?<timecode>[0-9:;]+)\t(?<data>(?:[0-9a-fA-F]{4} ?)+)$/.freeze
STANDARD_CHARACTER_MAP =

Map of standard characters that do not match the standard ASCII codes to their corresponding unicode characters

{
  '\''   => '', # CEA-608-B says to use curly apostrophe
  '*'    => 'á',
  '\\'   => 'é',
  '^'    =>	'í',
  '_'    =>	'ó',
  '`'    =>	'ú',
  '{'    =>	'ç',
  '|'    =>	'÷',
  '}'    =>	'Ñ',
  '~'    =>	'ñ',
  "\x7f" =>	''
}
SPECIAL_CHARACTER_MAP =

Map of special characters to unicode codepoints 0x39 transparent space is handled specially since it is not a real character

Hash[%w[® ° ½ ¿  ¢ £  à _ è á ê î ô û].each_with_index.map { |char, i| [0x30 + i, char] }].freeze
EXTENDED_CHARACTER_MAPS =

Extended character maps for Western European languages and box drawing

Hash[%w[Á É Ó Ú Ü ü ‘ ¡ * ' ─ © ℠ · “ ” À Â Ç È Ê Ë ë Î Ï ï Ô Ù ù Û « »].each_with_index.map { |char, i| [0x20 + i, char] }].freeze,
  Hash[%w[Ã ã Í Ì ì Ò ò Õ õ { } \\ ^ _ | ~ Ä ä Ö ö ß ¥ ¤ │ Å å Ø ø ┌ ┐ └ ┘].each_with_index.map { |char, i| [0x20 + i, char] }].freeze
].freeze
PREAMBLE_ADDRESS_CODE_ROW_MAP =

Map of preamble address code high bytes to their corresponding base row numbers (counted from 0)

{
  0x10 => 10,
  0x11 => 0,
  0x12 => 2,
  0x13 => 11,
  0x14 => 13,
  0x15 => 4,
  0x16 => 6,
  0x17 => 8
}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#captionsObject (readonly)

Actual conversion result



301
302
303
# File 'lib/subconv/scc/reader.rb', line 301

def captions
  @captions
end

Instance Method Details

#read(io, fps, check_parity = true) ⇒ Object

Read an SCC file from the IO object io for a video



304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
# File 'lib/subconv/scc/reader.rb', line 304

def read(io, fps, check_parity = true)
  # Initialize new grids for character storage
  @foreground_grid = Grid.new
  @background_grid = Grid.new
  # Initialize state
  @state = State.default
  @captions = []
  @now = Timecode.new(0, fps)
  @data_channel = 0

  update_active_grid

  magic = io.readline.chomp!
  fail InvalidFormatError, 'File does not start with "' + Scc::FILE_MAGIC + '"' unless Scc::FILE_MAGIC == magic

  io.each_line do |line|
    line.chomp!
    # Skip empty lines between the commands
    next if line.empty?

    line_data = LINE_REGEXP.match(line)
    fail InvalidFormatError, "Invalid line \"#{line}\"" if line_data.nil?

    # Parse timecode
    old_time = @now
    timecode = Timecode.new(line_data[:timecode], fps)
    @now = timecode
    fail InvalidFormatError, 'New timecode is behind last time' if @now < old_time

    # Parse data words
    parse_data(line_data[:data], check_parity)
  end
end