1 /*
2  * EIT table parser and generator
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 
14 #include "tsfuncs.h"
15 
ts_eit_alloc()16 struct ts_eit *ts_eit_alloc() {
17 	struct ts_eit *eit = calloc(1, sizeof(struct ts_eit));
18 	eit->section_header = ts_section_data_alloc();
19 	eit->streams_max = 128;
20 	eit->streams = calloc(eit->streams_max, sizeof(void *));
21 	return eit;
22 }
23 
ts_eit_streams_data_free(struct ts_eit * eit)24 static void ts_eit_streams_data_free(struct ts_eit *eit) {
25 	int i;
26 	for (i=0;i<eit->streams_num;i++) {
27 		if (eit->streams[i]) {
28 			FREE(eit->streams[i]->descriptor_data);
29 			FREE(eit->streams[i]);
30 		}
31 	}
32 }
33 
ts_eit_clear(struct ts_eit * eit)34 void ts_eit_clear(struct ts_eit *eit) {
35 	if (!eit)
36 		return;
37 	// save
38 	struct ts_section_header *section_header = eit->section_header;
39 	struct ts_eit_stream **streams = eit->streams;
40 	int streams_max = eit->streams_max;
41 	// free
42 	ts_eit_streams_data_free(eit);
43 	// clear
44 	ts_section_data_clear(section_header);
45 	memset(eit, 0, sizeof(struct ts_eit));
46 	// restore
47 	eit->section_header = section_header;
48 	eit->streams = streams;
49 	eit->streams_max = streams_max;
50 }
51 
ts_eit_free(struct ts_eit ** peit)52 void ts_eit_free(struct ts_eit **peit) {
53 	struct ts_eit *eit = *peit;
54 	if (eit) {
55 		ts_section_data_free(&eit->section_header);
56 		ts_eit_streams_data_free(eit);
57 		FREE(eit->streams);
58 		FREE(*peit);
59 	}
60 }
61 
ts_eit_push_packet(struct ts_eit * eit,uint8_t * ts_packet)62 struct ts_eit *ts_eit_push_packet(struct ts_eit *eit, uint8_t *ts_packet) {
63 	struct ts_header ts_header;
64 	memset(&ts_header, 0, sizeof(struct ts_header));
65 
66 	if (ts_packet_header_parse(ts_packet, &ts_header)) {
67 		// EIT should be with PID 0x12
68 		if (ts_header.pid != 0x12)
69 			goto OUT;
70 		// Received PUSI packet before table END, clear the table to start gathering new one
71 		if (ts_header.pusi && eit->ts_header.pusi)
72 			ts_eit_clear(eit);
73 		if (!eit->ts_header.pusi)
74 			eit->ts_header = ts_header;
75 	}
76 
77 	if (ts_header.pusi) {
78 		struct ts_section_header section_header;
79 		memset(&section_header, 0, sizeof(struct ts_section_header));
80 
81 		uint8_t *section_data = ts_section_header_parse(ts_packet, &eit->ts_header, &section_header);
82 		if (!section_data) {
83 			memset(&eit->ts_header, 0, sizeof(struct ts_header));
84 			goto OUT;
85 		}
86 		// table_id should be 0x4e (event_information_section - actual_transport_stream, present/following)
87 		// table_id 0x50 - 0x5f    (event_information_section - actual_transport_stream, schedule)
88 		if (section_header.table_id != 0x4e && (section_header.table_id < 0x50 && section_header.table_id > 0x5f)) {
89 			memset(&eit->ts_header, 0, sizeof(struct ts_header));
90 			goto OUT;
91 		}
92 
93 		// Set correct section_header
94 		ts_section_header_parse(ts_packet, &eit->ts_header, eit->section_header);
95 	}
96 
97 	if (!eit->initialized) {
98 		ts_section_add_packet(eit->section_header, &ts_header, ts_packet);
99 		if (eit->section_header->initialized) {
100 			if (!ts_eit_parse(eit))
101 				goto ERROR;
102 		}
103 	}
104 
105 OUT:
106 	return eit;
107 
108 ERROR:
109 	ts_eit_clear(eit);
110 	return eit;
111 }
112 
113 
ts_eit_parse(struct ts_eit * eit)114 int ts_eit_parse(struct ts_eit *eit) {
115 	uint8_t *section_data = eit->section_header->data;
116 	int section_len = eit->section_header->data_len;
117 
118 	/* Table data (6 bytes) */
119 	eit->transport_stream_id			= (section_data[0] << 8) | section_data[1];	// 11111111 11111111
120 	eit->original_network_id			= (section_data[2] << 8) | section_data[3];	// 11111111 11111111
121 	eit->segment_last_section_number	= section_data[4];
122 	eit->last_table_id					= section_data[5];
123 
124 	uint8_t *stream_data = section_data + 6;		// +5 is to compensate for the above
125 	int stream_len       = section_len - 6 - 4;		// -4 for the CRC at the end
126 
127 	while (stream_len > 0) {
128 		if (eit->streams_num == eit->streams_max) {
129 			ts_LOGf("!!! Too many streams in EIT, max %d\n", eit->streams_max);
130 			break;
131 		}
132 
133 		struct ts_eit_stream *sinfo = calloc(1, sizeof(struct ts_eit_stream));
134 
135 		sinfo->event_id			 = (stream_data[0] << 8) | stream_data[1];
136 		sinfo->start_time_mjd	 = (stream_data[2] << 8) | stream_data[3];
137 
138 		sinfo->start_time_bcd	 = stream_data[4] << 16;
139 		sinfo->start_time_bcd	|= stream_data[5] << 8;
140 		sinfo->start_time_bcd	|= stream_data[6];
141 
142 		sinfo->duration_bcd		 = stream_data[7] << 16;
143 		sinfo->duration_bcd		|= stream_data[8] << 8;
144 		sinfo->duration_bcd		|= stream_data[9];
145 
146 		sinfo->running_status	 = stream_data[10] >> 5;								// 111xxxxx
147 		sinfo->free_CA_mode		 = (stream_data[10] &~ 0xE0) >> 4;						// xxx1xxxx
148 		sinfo->descriptor_size	 = ((stream_data[10] &~ 0xF0) << 8) | stream_data[11];	// 1111xxxx xxxxxxxx
149 
150 		stream_data += 12; // Compensate for the the above vars
151 		stream_len  -= 12 + sinfo->descriptor_size;
152 
153 		sinfo->descriptor_data = NULL;
154 		if (sinfo->descriptor_size > 0) {
155 			sinfo->descriptor_data = malloc(sinfo->descriptor_size);
156 			memcpy(sinfo->descriptor_data, stream_data, sinfo->descriptor_size);
157 		}
158 		eit->streams[eit->streams_num] = sinfo;
159 		eit->streams_num++;
160 
161 		stream_data += sinfo->descriptor_size;
162 	}
163 
164 	if (!ts_crc32_section_check(eit->section_header, "EIT"))
165 		return 0;
166 
167 	eit->initialized = 1;
168 	return 1;
169 }
170 
ts_eit_generate(struct ts_eit * eit,uint8_t ** ts_packets,int * num_packets)171 void ts_eit_generate(struct ts_eit *eit, uint8_t **ts_packets, int *num_packets) {
172 	uint8_t *secdata = ts_section_data_alloc_section();
173 	ts_section_header_generate(secdata, eit->section_header, 0);
174 	int curpos = 8; // Compensate for the section header, frist data byte is at offset 8
175 
176 
177 	secdata[curpos + 0] = eit->transport_stream_id >> 8;			// xxxxxxxx xxxxxxxx
178 	secdata[curpos + 1] = eit->transport_stream_id &~ 0xff00;
179 
180 	secdata[curpos + 2] = eit->original_network_id >> 8;			// xxxxxxxx xxxxxxxx
181 	secdata[curpos + 3] = eit->original_network_id &~ 0xff00;
182 
183 	secdata[curpos + 4] = eit->segment_last_section_number;
184 	secdata[curpos + 5] = eit->last_table_id;
185 	curpos += 6; // For the fields above
186 
187 	int i;
188 	for(i=0;i<eit->streams_num;i++) {
189 		struct ts_eit_stream *stream = eit->streams[i];
190 		secdata[curpos + 0]  = stream->event_id >> 8;			// xxxxxxxx xxxxxxxx
191 		secdata[curpos + 1]  = stream->event_id &~ 0xff00;
192 
193 		secdata[curpos + 2]  = stream->start_time_mjd >> 8;		// xxxxxxxx xxxxxxxx
194 		secdata[curpos + 3]  = stream->start_time_mjd &~ 0xff00;
195 
196 		secdata[curpos + 4]  = stream->start_time_bcd >> 16;
197 		secdata[curpos + 5]  =(stream->start_time_bcd >> 8) &~ 0xff00;
198 		secdata[curpos + 6]  = stream->start_time_bcd &~ 0xffff00;
199 
200 		secdata[curpos + 7]  = stream->duration_bcd >> 16;
201 		secdata[curpos + 8]  =(stream->duration_bcd >> 8) &~ 0xff00;
202 		secdata[curpos + 9]  = stream->duration_bcd &~ 0xffff00;
203 
204 		secdata[curpos +10]  = stream->running_status << 5;		// 111xxxxx
205 		secdata[curpos +10] |= stream->free_CA_mode   << 4;		// xxx1xxxx
206 		secdata[curpos +10] |= stream->descriptor_size >> 8;		// 1111xxxx xxxxxxxx
207 		secdata[curpos +11]  = stream->descriptor_size &~ 0xff00;
208 		curpos += 12; // Compensate for the above
209 
210 		if (stream->descriptor_size > 0) {
211 			memcpy(secdata + curpos, stream->descriptor_data, stream->descriptor_size);
212 			curpos += stream->descriptor_size;
213 		}
214 	}
215 	eit->section_header->CRC = ts_section_data_calculate_crc(secdata, curpos);
216 	curpos += 4; // CRC
217 
218 	ts_section_data_gen_ts_packets(&eit->ts_header, secdata, curpos, eit->section_header->pointer_field, ts_packets, num_packets);
219 
220 	FREE(secdata);
221 }
222 
ts_eit_check_generator(struct ts_eit * eit)223 void ts_eit_check_generator(struct ts_eit *eit) {
224 	struct ts_eit *eit1 = ts_eit_alloc();
225 	int i;
226 	for (i=0;i<eit->section_header->num_packets;i++) {
227 		eit1 = ts_eit_push_packet(eit1, eit->section_header->packet_data + (i * TS_PACKET_SIZE));
228 	}
229 	ts_compare_data("EIT (tspacket->struct)",
230 		eit1->section_header->packet_data,
231 		eit->section_header->packet_data,
232 		eit->section_header->num_packets * TS_PACKET_SIZE);
233 	ts_eit_free(&eit1);
234 
235 	uint8_t *ts_packets;
236 	int num_packets;
237 	ts_eit_generate(eit, &ts_packets, &num_packets);
238 	if (num_packets != eit->section_header->num_packets) {
239 		ts_LOGf("ERROR: num_packets:%d != sec->num_packets:%d\n", num_packets, eit->section_header->num_packets);
240 	}
241 	ts_compare_data("EIT (struct->tspacket)", eit->section_header->packet_data, ts_packets, num_packets * TS_PACKET_SIZE);
242 	free(ts_packets);
243 }
244 
ts_eit_regenerate_packets(struct ts_eit * eit)245 void ts_eit_regenerate_packets(struct ts_eit *eit) {
246 	uint8_t *ts_packets;
247 	int num_packets;
248 	ts_eit_generate(eit, &ts_packets, &num_packets);
249 	FREE(eit->section_header->packet_data);
250 	eit->section_header->packet_data = ts_packets;
251 	eit->section_header->num_packets = num_packets;
252 }
253 
ts_eit_copy(struct ts_eit * eit)254 struct ts_eit *ts_eit_copy(struct ts_eit *eit) {
255 	struct ts_eit *neweit = ts_eit_alloc();
256 	int i;
257 	for (i=0;i<eit->section_header->num_packets; i++) {
258 		neweit = ts_eit_push_packet(neweit, eit->section_header->packet_data + (i * TS_PACKET_SIZE));
259 	}
260 	if (neweit->initialized) {
261 		return neweit;
262 	} else {
263 		ts_LOGf("Error copying EIT!\n");
264 		ts_eit_free(&neweit);
265 		return NULL;
266 	}
267 }
268 
ts_eit_dump(struct ts_eit * eit)269 void ts_eit_dump(struct ts_eit *eit) {
270 	struct ts_section_header *sect = eit->section_header;
271 	int i;
272 
273 	ts_section_dump(sect);
274 
275 	ts_LOGf("  * EIT data\n");
276 	ts_LOGf("    * PID             : 0x%04x (%d)\n", eit->ts_header.pid, eit->ts_header.pid);
277 	ts_LOGf("    * ts_stream_id    : 0x%04x (%d)\n", eit->transport_stream_id, eit->transport_stream_id);
278 	ts_LOGf("    * org_network_id  : 0x%04x (%d)\n", eit->original_network_id, eit->original_network_id);
279 	ts_LOGf("    * seg_last_sec_num: %d\n", eit->segment_last_section_number);
280 	ts_LOGf("    * last_table_id   : 0x%02x (%d)\n", eit->last_table_id, eit->last_table_id);
281 	ts_LOGf("    * num_streams     : %d\n", eit->streams_num);
282 
283 	for(i=0;i<eit->streams_num;i++) {
284 		struct ts_eit_stream *stream = eit->streams[i];
285 		int hour, min, sec;
286 		struct tm tm;
287 		ts_time_decode_mjd(stream->start_time_mjd, stream->start_time_bcd, &tm);
288 		ts_time_decode_bcd(stream->duration_bcd, NULL, &hour, &min, &sec);
289 		ts_LOGf("    * Event_id [%02d/%02d]\n", i+1, eit->streams_num);
290 		ts_LOGf("      - Event_id  : 0x%04x (%d)\n", stream->event_id, stream->event_id);
291 		ts_LOGf("      - Start_time: %04d-%02d-%02d %02d:%02d:%02d (0x%04x%06x) ts: %ld\n",
292 			tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
293 			stream->start_time_mjd,
294 			stream->start_time_bcd, timegm(&tm));
295 		ts_LOGf("      - Duration  : %02d:%02d:%02d (0x%06x)\n",
296 			hour, min, sec,
297 			stream->duration_bcd);
298 		ts_LOGf("      - Running_status: %d free_CA_mode: %d /desc_size: %d/\n",
299 			stream->running_status,
300 			stream->free_CA_mode,
301 			stream->descriptor_size);
302 
303 		if (stream->descriptor_data) {
304 			ts_descriptor_dump(stream->descriptor_data, stream->descriptor_size);
305 		}
306 	}
307 
308 	ts_eit_check_generator(eit);
309 }
310 
ts_eit_is_same(struct ts_eit * eit1,struct ts_eit * eit2)311 int ts_eit_is_same(struct ts_eit *eit1, struct ts_eit *eit2) {
312 	if (eit1 == eit2) return 1; // Same
313 	if ((!eit1 && eit2) || (eit1 && !eit2)) return 0; // Not same (one is NULL)
314 	return ts_section_is_same(eit1->section_header, eit2->section_header);
315 }
316