tsparser 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +20 -0
- data/README.rdoc +16 -0
- data/lib/arib_string_decoder.rb +441 -0
- data/lib/binary.rb +202 -0
- data/lib/definition/arib_duration.rb +19 -0
- data/lib/definition/arib_string.rb +327 -0
- data/lib/definition/arib_time.rb +41 -0
- data/lib/definition/descriptor.rb +27 -0
- data/lib/definition/descriptor/audio_component_descriptor.rb +12 -0
- data/lib/definition/descriptor/ca_contract_information_descriptor.rb +12 -0
- data/lib/definition/descriptor/component_descriptor.rb +18 -0
- data/lib/definition/descriptor/content_descriptor.rb +37 -0
- data/lib/definition/descriptor/data_content_descriptor.rb +12 -0
- data/lib/definition/descriptor/digital_copy_control_descriptor.rb +12 -0
- data/lib/definition/descriptor/event_group_descriptor.rb +12 -0
- data/lib/definition/descriptor/extended_event_descriptor.rb +52 -0
- data/lib/definition/descriptor/short_event_descriptor.rb +17 -0
- data/lib/definition/descriptor/unknown_descriptor.rb +13 -0
- data/lib/definition/descriptor_list.rb +17 -0
- data/lib/definition/eit_event.rb +21 -0
- data/lib/definition/event_information_section.rb +53 -0
- data/lib/definition/event_list.rb +17 -0
- data/lib/definition/transport_packet.rb +68 -0
- data/lib/epg.rb +29 -0
- data/lib/parsing.rb +63 -0
- data/lib/psi_section_reader.rb +39 -0
- data/lib/ts.rb +41 -0
- data/lib/tsparser.rb +75 -0
- metadata +72 -0
@@ -0,0 +1,41 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
module TSparser
|
3
|
+
class AribTime
|
4
|
+
require 'date'
|
5
|
+
require 'time'
|
6
|
+
|
7
|
+
def initialize(binary)
|
8
|
+
@mjd = binary.read_byte_as_integer(2)
|
9
|
+
@hour = binary.read_bit_as_integer(4) * 10 + binary.read_bit_as_integer(4)
|
10
|
+
@min = binary.read_bit_as_integer(4) * 10 + binary.read_bit_as_integer(4)
|
11
|
+
@sec = binary.read_bit_as_integer(4) * 10 + binary.read_bit_as_integer(4)
|
12
|
+
end
|
13
|
+
|
14
|
+
def date
|
15
|
+
return @date ||= convert_mjd_to_date(@mjd)
|
16
|
+
end
|
17
|
+
|
18
|
+
# ARIB STD-B10 2, appendix-C
|
19
|
+
def convert_mjd_to_date(mjd)
|
20
|
+
y_ = ((mjd - 15078.2) / 365.25).to_i
|
21
|
+
m_ = ((mjd - 14956.1 - (y_ * 365.25).to_i) / 30.6001).to_i
|
22
|
+
d = mjd - 14956 - (y_ * 365.25).to_i - (m_ * 30.6001).to_i
|
23
|
+
k = (m_ == 14 || m_ == 15) ? 1 : 0
|
24
|
+
y = y_ + k
|
25
|
+
m = m_ - 1 - k * 12
|
26
|
+
return Date.new(1900 + y, m, d)
|
27
|
+
end
|
28
|
+
|
29
|
+
def date_str
|
30
|
+
return sprintf("%02d/%02d/%02d", date.year, date.month, date.day)
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_s
|
34
|
+
return sprintf("%s %02d:%02d:%02d +0900", date_str, @hour, @min, @sec)
|
35
|
+
end
|
36
|
+
|
37
|
+
def to_time
|
38
|
+
return Time.parse(to_s)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
module TSparser
|
3
|
+
class Descriptor
|
4
|
+
|
5
|
+
# ARIB STD-B10 Table5-3
|
6
|
+
DescriptorTable = {
|
7
|
+
0x4D => TSparser::ShortEventDescriptor,
|
8
|
+
0x4E => TSparser::ExtendedEventDescriptor,
|
9
|
+
0x50 => TSparser::ComponentDescriptor,
|
10
|
+
0x54 => TSparser::ContentDescriptor,
|
11
|
+
0xC1 => TSparser::DigitalCopyControlDescriptor,
|
12
|
+
0xC4 => TSparser::AudioComponentDescriptor,
|
13
|
+
0xC7 => TSparser::DataContentDescriptor,
|
14
|
+
0xCB => TSparser::CAContractInformationDescriptor, # Defined in ARIB STD-B25
|
15
|
+
0xD6 => TSparser::EventGroupDescriptor
|
16
|
+
}
|
17
|
+
DescriptorTable.default = TSparser::UnknownDescriptor
|
18
|
+
|
19
|
+
def self.new(binary)
|
20
|
+
now_point = binary.bit_pointer / 8
|
21
|
+
descriptor_tag = binary.b(now_point + 0)
|
22
|
+
descriptor_length = binary.b(now_point + 1)
|
23
|
+
descriptor_whole_binary = binary.read_bit_as_binary(descriptor_length * 8 + 16)
|
24
|
+
return DescriptorTable[descriptor_tag].new(descriptor_whole_binary)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
module TSparser
|
3
|
+
class ComponentDescriptor
|
4
|
+
include Parsing
|
5
|
+
|
6
|
+
def_parsing do
|
7
|
+
read :descriptor_tag, Integer, 8
|
8
|
+
read :descriptor_length, Integer, 8
|
9
|
+
read :reserved_future_use, Binary, 4
|
10
|
+
read :stream_content, Integer, 4
|
11
|
+
read :component_type, Integer, 8
|
12
|
+
read :component_tag, Integer, 8
|
13
|
+
read :iso_639_language_code, String, 24
|
14
|
+
read :text, AribString, descriptor_length * 8 - 48
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
module TSparser
|
3
|
+
class ContentDescriptor
|
4
|
+
include Parsing
|
5
|
+
|
6
|
+
def_parsing do
|
7
|
+
read :descriptor_tag, Integer, 8
|
8
|
+
read :descriptor_length, Integer, 8
|
9
|
+
read :contents, ContentList, descriptor_length * 8
|
10
|
+
end
|
11
|
+
|
12
|
+
class ContentList
|
13
|
+
|
14
|
+
def initialize(binary)
|
15
|
+
@contents = []
|
16
|
+
while binary.readable?
|
17
|
+
@contents << Content.new(binary)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def each(&block)
|
22
|
+
@contents.each(&block)
|
23
|
+
end
|
24
|
+
|
25
|
+
class Content
|
26
|
+
include Parsing
|
27
|
+
|
28
|
+
def_parsing do
|
29
|
+
read :content_nibble_level_1, Integer, 4
|
30
|
+
read :content_nibble_level_2, Integer, 4
|
31
|
+
read :user_nibble, Integer, 4
|
32
|
+
read :user_nibble, Integer, 4
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
module TSparser
|
3
|
+
class ExtendedEventDescriptor
|
4
|
+
include Parsing
|
5
|
+
|
6
|
+
def_parsing do
|
7
|
+
read :descriptor_tag, Integer, 8
|
8
|
+
read :descriptor_length, Integer, 8
|
9
|
+
read :descriptor_number, Integer, 4
|
10
|
+
read :last_descriptor_number, Integer, 4
|
11
|
+
read :iso_639_language_code, String, 24
|
12
|
+
read :length_of_items, Integer, 8
|
13
|
+
read :item_map, ItemHash, length_of_items * 8
|
14
|
+
read :text_length, Integer, 8
|
15
|
+
read :text, AribString, text_length * 8
|
16
|
+
end
|
17
|
+
|
18
|
+
class ItemHash
|
19
|
+
def initialize(binary)
|
20
|
+
@item_map = Hash.new
|
21
|
+
while binary.readable?
|
22
|
+
item = Item.new(binary)
|
23
|
+
@item_map[item.item_description.to_utf_8] = item.item.to_utf_8
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def [](key)
|
28
|
+
return @item_map[key]
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_h
|
32
|
+
return @item_map.dup
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_s
|
36
|
+
return @item_map.to_s
|
37
|
+
end
|
38
|
+
|
39
|
+
class Item
|
40
|
+
include Parsing
|
41
|
+
|
42
|
+
def_parsing(false) do
|
43
|
+
read :item_description_length, Integer, 8
|
44
|
+
read :item_description, AribString, item_description_length * 8
|
45
|
+
read :item_length, Integer, 8
|
46
|
+
read :item, AribString, item_length * 8
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
module TSparser
|
3
|
+
class ShortEventDescriptor
|
4
|
+
include Parsing
|
5
|
+
|
6
|
+
def_parsing do
|
7
|
+
read :descriptor_tag, Integer, 8
|
8
|
+
read :descriptor_length, Integer, 8
|
9
|
+
read :iso_639_language_code, String, 24
|
10
|
+
read :event_name_length, Integer, 8
|
11
|
+
read :event_name, AribString, event_name_length * 8
|
12
|
+
read :text_length, Integer, 8
|
13
|
+
read :text, AribString, text_length * 8
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
module TSparser
|
3
|
+
class DescriptorList
|
4
|
+
include Enumerable
|
5
|
+
|
6
|
+
def initialize(binary)
|
7
|
+
@descriptors = []
|
8
|
+
while binary.readable?
|
9
|
+
@descriptors << Descriptor.new(binary)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def each(&block)
|
14
|
+
@descriptors.each(&block)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
module TSparser
|
3
|
+
class EITEvent
|
4
|
+
include Parsing
|
5
|
+
|
6
|
+
# define data-structure of event_information_section
|
7
|
+
# this is following ARIB-STD-b10v4_9 - 88p
|
8
|
+
def_parsing(false) do
|
9
|
+
read :event_id, Integer, 16
|
10
|
+
read :start_time, AribTime, 40
|
11
|
+
read :duration, AribDuration, 24
|
12
|
+
read :running_status, Integer, 3
|
13
|
+
read :free_ca_mode, Integer, 1
|
14
|
+
read :descriptors_loop_length, Integer, 12
|
15
|
+
read :descriptors, DescriptorList, descriptors_loop_length * 8
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
module TSparser
|
3
|
+
class EventInformationSection
|
4
|
+
include Parsing
|
5
|
+
|
6
|
+
def self.section_length_enough?(section_binary)
|
7
|
+
section_length = (section_binary.b(1, 0..3) << 8) + section_binary.b(2)
|
8
|
+
return section_binary.length >= section_length + 3
|
9
|
+
end
|
10
|
+
|
11
|
+
# define data-structure of event_information_section
|
12
|
+
# this is following ARIB-STD-b10v4_9 - 88p
|
13
|
+
def_parsing do
|
14
|
+
read :table_id, Integer, 8
|
15
|
+
read :section_syntax_indicator, Integer, 1
|
16
|
+
read :reserved_future_use, Integer, 1
|
17
|
+
read :reserved1, Integer, 2
|
18
|
+
read :section_length, Integer, 12
|
19
|
+
read :service_id, Integer, 16
|
20
|
+
read :reserved2, Integer, 2
|
21
|
+
read :version_number, Integer, 5
|
22
|
+
read :current_next_indicator, Integer, 1
|
23
|
+
read :section_number, Integer, 8
|
24
|
+
read :last_section_number, Integer, 8
|
25
|
+
read :transport_stream_id, Integer, 16
|
26
|
+
read :original_network_id, Integer, 16
|
27
|
+
read :segment_last_section_number, Integer, 8
|
28
|
+
read :last_table_id, Integer, 8
|
29
|
+
read :events, EITEventList, section_length * 8 - 88 - 32
|
30
|
+
read :crc_32, Integer, 32
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_epg
|
34
|
+
epg = EPG.new
|
35
|
+
events.each do |event|
|
36
|
+
attr_hash = {
|
37
|
+
:event_id => event.event_id,
|
38
|
+
:start_time => event.start_time.to_s,
|
39
|
+
:duration => event.duration.to_sec
|
40
|
+
}
|
41
|
+
event.descriptors.each do |desc|
|
42
|
+
case desc
|
43
|
+
when ShortEventDescriptor
|
44
|
+
attr_hash[:name] = desc.event_name.to_utf_8
|
45
|
+
attr_hash[:description] = desc.text.to_utf_8
|
46
|
+
end
|
47
|
+
end
|
48
|
+
epg.add(event.event_id, attr_hash) if attr_hash[:name]
|
49
|
+
end
|
50
|
+
return epg
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
module TSparser
|
3
|
+
class EITEventList
|
4
|
+
include Enumerable
|
5
|
+
|
6
|
+
def initialize(binary)
|
7
|
+
@events = []
|
8
|
+
while binary.readable?
|
9
|
+
@events << EITEvent.new(binary)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def each(&block)
|
14
|
+
@events.each(&block)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
module TSparser
|
3
|
+
|
4
|
+
# Define data-structure of transport packet.
|
5
|
+
# This is following
|
6
|
+
# iso13818-1, 2.4.3.2, Table2-2 and 2.4.3.5, Table2-6 (adaptation field).
|
7
|
+
class TransportPacket
|
8
|
+
include Parsing
|
9
|
+
|
10
|
+
def_parsing do
|
11
|
+
read :sync_byte, Integer, 8
|
12
|
+
read :transport_error_indicator, Integer, 1
|
13
|
+
read :payload_unit_start_indicator, Integer, 1
|
14
|
+
read :transport_priority, Integer, 1
|
15
|
+
read :pid, Integer, 13
|
16
|
+
read :transport_scrambling_control, Integer, 2
|
17
|
+
read :adaptation_field_control, Integer, 2
|
18
|
+
read :continuity_counter, Integer, 4
|
19
|
+
if adaptation_field_control[1] == 1
|
20
|
+
read :adaptation_field_length, Integer, 8
|
21
|
+
if adaptation_field_length > 0
|
22
|
+
read :adaptation_field, AdaptationField, adaptation_field_length * 8
|
23
|
+
end
|
24
|
+
end
|
25
|
+
if adaptation_field_control[0] == 1
|
26
|
+
read :payload, Binary, rest_all
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Especial parsing of PID for fast calculation.
|
31
|
+
def pid
|
32
|
+
return @pid ||= (@binary.b(1, 0..4) << 8) + @binary.b(2)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Define data-structure of adaptation field in transport packet.
|
37
|
+
# This is following
|
38
|
+
# iso13818-1, 2.4.3.5, Table2-6.
|
39
|
+
class AdaptationField
|
40
|
+
include Parsing
|
41
|
+
|
42
|
+
def_parsing do
|
43
|
+
read :discontinuity_indicator, Integer, 1
|
44
|
+
read :random_acceses_indicator, Integer, 1
|
45
|
+
read :elementary_stream_priority_indicator, Integer, 1
|
46
|
+
read :pcr_flag, Integer, 1
|
47
|
+
read :opcr_flag, Integer, 1
|
48
|
+
read :splicing_point_flag, Integer, 1
|
49
|
+
read :transport_private_data_flag, Integer, 1
|
50
|
+
read :adaptation_field_extension_flag, Integer, 1
|
51
|
+
if pcr_flag == 1
|
52
|
+
|
53
|
+
end
|
54
|
+
if opcr_flag == 1
|
55
|
+
|
56
|
+
end
|
57
|
+
if splicing_point_flag == 1
|
58
|
+
|
59
|
+
end
|
60
|
+
if transport_private_data_flag == 1
|
61
|
+
|
62
|
+
end
|
63
|
+
if adaptation_field_extension_flag == 1
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|