1 /*
2  * PSI Section functions
3  * Copyright (C) 2010-2011 Unix Solutions Ltd.
4  *
5  * Released under MIT license.
6  * See LICENSE-MIT.txt for license terms.
7  */
8 #include <stdio.h>
9 #include <unistd.h>
10 #include <netdb.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <ctype.h>
14 
15 #include "tsfuncs.h"
16 
17 #define have_left(X) \
18 	do { if (data + (X) > data_end) return NULL; } while(0)
19 
ts_section_header_set_private_vars(struct ts_section_header * ts_section_header)20 void ts_section_header_set_private_vars(struct ts_section_header *ts_section_header) {
21 	if (ts_section_header->section_syntax_indicator) {
22 		ts_section_header->data     = ts_section_header->section_data   + 3 + 5;	// Skip header and extended header
23 		ts_section_header->data_len = ts_section_header->section_length - 9;		// 5 for extended header, 4 for crc at the end
24 	} else {
25 		ts_section_header->data     = ts_section_header->section_data + 3; // Skip header
26 		ts_section_header->data_len = ts_section_header->section_length;
27 	}
28 	ts_section_header->section_data_len = ts_section_header->section_length + 3;	// 3 for section header
29 }
30 
ts_section_header_parse(uint8_t * ts_packet,struct ts_header * ts_header,struct ts_section_header * ts_section_header)31 uint8_t *ts_section_header_parse(uint8_t *ts_packet, struct ts_header *ts_header, struct ts_section_header *ts_section_header) {
32 	uint8_t *data = ts_packet + ts_header->payload_offset;
33 	uint8_t *data_end = ts_packet + TS_PACKET_SIZE;
34 
35 	have_left(ts_section_header->pointer_field + 1);
36 	ts_section_header->pointer_field = data[0];
37 	data += ts_section_header->pointer_field + 1;
38 
39 	have_left(3);
40 	ts_section_header->table_id                 = data[0];
41 	ts_section_header->section_syntax_indicator = data[1] >> 7;				// x1111111
42 	ts_section_header->private_indicator        = (data[1] &~ 0xBF) >> 6;	// 1x111111
43 	ts_section_header->reserved1                = (data[1] &~ 0xCF) >> 4;	// 11xx1111
44 	ts_section_header->section_length           = ((data[1] &~ 0xF0) << 8) | data[2]; // 1111xxxx xxxxxxxx
45 	data += 3;
46 
47 	if (ts_section_header->section_length == 0)
48 		return NULL;
49 
50 	// Stuffing table, ignore.
51 	if (ts_section_header->table_id == 0x72)
52 		return NULL;
53 
54 	if (ts_section_header->section_syntax_indicator) {
55 		have_left(5);
56 		ts_section_header->ts_id_number             = (data[0] << 8) | data[1]; // xxxxxxx xxxxxxx
57 		ts_section_header->reserved2                =  data[2] >> 6;			// xx111111
58 		ts_section_header->version_number           = (data[2] &~ 0xC1) >> 1;	// 11xxxxx1
59 		ts_section_header->current_next_indicator   = data[2] &~ 0xFE;			// 1111111x
60 		ts_section_header->section_number           = data[3];
61 		ts_section_header->last_section_number      = data[4];
62 		data += 5;
63 	}
64 
65 	ts_section_header_set_private_vars(ts_section_header);
66 
67 	return data;
68 }
69 
70 #undef have_left
71 
ts_section_header_generate(uint8_t * ts_packet,struct ts_section_header * ts_section_header,uint8_t start)72 void ts_section_header_generate(uint8_t *ts_packet, struct ts_section_header *ts_section_header, uint8_t start) {
73 	ts_packet[start + 0] = ts_section_header->table_id;
74 
75 	ts_packet[start + 1]  = ts_section_header->section_syntax_indicator << 7;		// x1111111
76 	ts_packet[start + 1] |= ts_section_header->private_indicator        << 6;		// 1x111111
77 	ts_packet[start + 1] |= ts_section_header->reserved1                << 4;		// 11xx1111
78 	ts_packet[start + 1] |= ts_section_header->section_length           >> 8;		// 1111xxxx xxxxxxxx
79 	ts_packet[start + 2]  = ts_section_header->section_length           &~ 0xff00;	// 1111xxxx xxxxxxxx
80 
81 	if (ts_section_header->section_syntax_indicator) { // Extended table syntax
82 		ts_packet[start + 3]  = ts_section_header->ts_id_number             >> 8;		// xxxxxxxx xxxxxxxx
83 		ts_packet[start + 4]  = ts_section_header->ts_id_number             &~ 0xff00;
84 
85 		ts_packet[start + 5]  = ts_section_header->reserved2                 << 6;		// xx111111
86 		ts_packet[start + 5] |= ts_section_header->version_number            << 1;		// 11xxxxx1
87 		ts_packet[start + 5] |= ts_section_header->current_next_indicator;				// 1111111x
88 
89 		ts_packet[start + 6] = ts_section_header->section_number;
90 		ts_packet[start + 7] = ts_section_header->last_section_number;
91 	}
92 }
93 
ts_section_is_same(struct ts_section_header * s1,struct ts_section_header * s2)94 int ts_section_is_same(struct ts_section_header *s1, struct ts_section_header *s2) {
95 //	ts_LOGf("s1->table_id=%d s2->table_id=%d\n", s1->table_id, s2->table_id);
96 	if (s1->table_id != s2->table_id)
97 		return 0;
98 
99 //	ts_LOGf("s1->version_number=%d s2->version_number=%d\n", s1->version_number, s2->version_number);
100 	if (s1->version_number != s2->version_number)
101 		return 0;
102 
103 //	ts_LOGf("s1->section_number=%d s2->section_number=%d\n", s1->section_number, s2->section_number);
104 	if (s1->section_number != s2->section_number)
105 		return 0;
106 
107 //	ts_LOGf("s1->section_length=%d s2->section_length=%d\n", s1->section_number, s2->section_number);
108 	if (s1->section_length != s2->section_length)
109 		return 0;
110 
111 	return memcmp(s1->section_data, s2->section_data, s1->section_length) == 0;
112 }
113 
114 #define IN(x, a, b) \
115 	(x >= a && x <= b)
116 
ts_section_header_dump(struct ts_section_header * t)117 void ts_section_header_dump(struct ts_section_header *t) {
118 	ts_LOGf("%s", "  * Section header\n");
119 	if (t->pointer_field)
120 	ts_LOGf("    - Pointer field      : %d\n", t->pointer_field);
121 	ts_LOGf("    - Table id           : %03x (%d) %s\n", t->table_id, t->table_id,
122 		t->table_id == 0x00         ? "program_association_section" :
123 		t->table_id == 0x01         ? "conditional_access_section" :
124 		t->table_id == 0x02         ? "program_map_section" :
125 		t->table_id == 0x03         ? "transport_stream_description_section" :
126 		IN(t->table_id, 0x04, 0x3f) ? "reserved" :
127 		t->table_id == 0x40         ? "network_information_section - actual_network" :
128 		t->table_id == 0x41         ? "network_information_section - other_network" :
129 		t->table_id == 0x42         ? "service_description_section - actual_transport_stream" :
130 		IN(t->table_id, 0x43, 0x45) ? "reserved for future use" :
131 		t->table_id == 0x46         ? "service_description_section - other_transport_stream" :
132 		IN(t->table_id, 0x47, 0x49) ? "reserved for future use" :
133 		t->table_id == 0x4a         ? "bouquet_association_section" :
134 		IN(t->table_id, 0x4b, 0x4d) ? "reserved for future use" :
135 		t->table_id == 0x4e         ? "event_information_section - actual_transport_stream, present/following" :
136 		t->table_id == 0x4f         ? "event_information_section - other_transport_stream, present/following" :
137 		IN(t->table_id, 0x50, 0x5f) ? "event_information_section - actual_transport_stream, schedule" :
138 		IN(t->table_id, 0x60, 0x6f) ? "event_information_section - other_transport_stream, schedule" :
139 		t->table_id == 0x70         ? "time_date_section" :
140 		t->table_id == 0x71         ? "running_status_section" :
141 		t->table_id == 0x72         ? "stuffing_section" :
142 		t->table_id == 0x73         ? "time_offset_section" :
143 		t->table_id == 0x74         ? "application information section (TS 102 812 [15])" :
144 		t->table_id == 0x75         ? "container section (TS 102 323 [13])" :
145 		t->table_id == 0x76         ? "related content section (TS 102 323 [13])" :
146 		t->table_id == 0x77         ? "content identifier section (TS 102 323 [13])" :
147 		t->table_id == 0x78         ? "MPE-FEC section (EN 301 192 [4])" :
148 		t->table_id == 0x79         ? "resolution notification section (TS 102 323 [13])" :
149 		IN(t->table_id, 0x79, 0x7d) ? "reserved for future use" :
150 		t->table_id == 0x7e         ? "discontinuity_information_section" :
151 		t->table_id == 0x7f         ? "section_information_section" :
152 		IN(t->table_id, 0x80, 0xfe) ? "user defined" :
153 		t->table_id == 0xff         ? "reserved" : "Impossible!"
154 	);
155 	ts_LOGf("    - Section length     : %03x (%d) [num_packets:%d]\n",
156 		t->section_length, t->section_length, t->num_packets);
157 	if (!t->section_syntax_indicator) {
158 		ts_LOGf("    - Private section syntax\n");
159 	} else {
160 		ts_LOGf("    - TS ID / Program No : %04x (%d)\n", t->ts_id_number, t->ts_id_number);
161 		ts_LOGf("    - Version number %d, current next %d, section number %d, last section number %d\n",
162 				t->version_number,
163 				t->current_next_indicator,
164 				t->section_number,
165 				t->last_section_number);
166 	}
167 	if (t->CRC && t->CRC != 0xffffffff)
168 		ts_LOGf("    - CRC                : 0x%08x\n", t->CRC);
169 }
170 
ts_section_dump(struct ts_section_header * sec)171 void ts_section_dump(struct ts_section_header *sec) {
172 	int i;
173 
174 	ts_LOGf("%s table\n",
175 		sec->table_id == 0x00         ? "PAT" :
176 		sec->table_id == 0x01         ? "CAT" :
177 		sec->table_id == 0x02         ? "PMT" :
178 		sec->table_id == 0x03         ? "TSDT" :
179 		IN(sec->table_id, 0x40, 0x41) ? "NIT" :
180 		sec->table_id == 0x42         ? "SDT" :
181 		sec->table_id == 0x46         ? "SDT" :
182 		sec->table_id == 0x4a         ? "BAT" :
183 		IN(sec->table_id, 0x4e, 0x6f) ? "EIT" :
184 		sec->table_id == 0x70         ? "TDT" :
185 		sec->table_id == 0x71         ? "RST" :
186 		sec->table_id == 0x72         ? "STUFFING" :
187 		sec->table_id == 0x73         ? "TOT" :
188 		sec->table_id == 0x7e         ? "DIS" :
189 		sec->table_id == 0x7f         ? "SIS" :
190 		IN(sec->table_id, 0x80, 0xfe) ? "USER_DEFINED" :
191 		sec->table_id == 0xff         ? "RESERVED" : "UNKNOWN"
192 	);
193 
194 	for (i=0;i<sec->num_packets;i++) {
195 		struct ts_header tshdr;
196 		ts_packet_header_parse(sec->packet_data + (i * TS_PACKET_SIZE), &tshdr);
197 		ts_packet_header_dump(&tshdr);
198 	}
199 	ts_section_header_dump(sec);
200 }
201 
202 #undef IN
203