Browse Source

Initial import

Georgi Chorbadzhiyski 9 years ago
commit
9053e9e67e
29 changed files with 5448 additions and 0 deletions
  1. 2 0
      .gitignore
  2. 35 0
      Makefile
  3. 25 0
      log.c
  4. 9 0
      log.h
  5. 435 0
      tsdata.h
  6. 422 0
      tsfuncs.c
  7. 238 0
      tsfuncs.h
  8. 40 0
      tsfuncs_crc.c
  9. 484 0
      tsfuncs_descriptors.c
  10. 297 0
      tsfuncs_eit.c
  11. 188 0
      tsfuncs_eit_desc.c
  12. 51 0
      tsfuncs_eit_test.c
  13. 184 0
      tsfuncs_misc.c
  14. 267 0
      tsfuncs_nit.c
  15. 179 0
      tsfuncs_nit_desc.c
  16. 241 0
      tsfuncs_pat.c
  17. 116 0
      tsfuncs_pat_desc.c
  18. 39 0
      tsfuncs_pat_test.c
  19. 544 0
      tsfuncs_pes.c
  20. 147 0
      tsfuncs_pes_data.c
  21. 130 0
      tsfuncs_pes_es.c
  22. 331 0
      tsfuncs_pmt.c
  23. 235 0
      tsfuncs_sdt.c
  24. 128 0
      tsfuncs_sdt_desc.c
  25. 18 0
      tsfuncs_sdt_test.c
  26. 118 0
      tsfuncs_section_data.c
  27. 134 0
      tsfuncs_sections.c
  28. 324 0
      tsfuncs_tdt.c
  29. 87 0
      tsfuncs_time.c

+ 2 - 0
.gitignore View File

@@ -0,0 +1,2 @@
1
+*.o
2
+*.a

+ 35 - 0
Makefile View File

@@ -0,0 +1,35 @@
1
+CC = $(CROSS)$(TARGET)gcc
2
+LINK = $(CROSS)$(TARGET)ld -o
3
+LIBRARY_LINK_OPTS =  -L. -r
4
+CFLAGS = -ggdb -D_GNU_SOURCE -Wall -Wextra -Wshadow -Wformat-security -O2
5
+RM = /bin/rm -f
6
+Q=@
7
+
8
+OBJS = log.o tsfuncs.o tsfuncs_crc.o tsfuncs_misc.o tsfuncs_time.o \
9
+	tsfuncs_sections.o tsfuncs_section_data.o \
10
+	tsfuncs_descriptors.o \
11
+	tsfuncs_pat.o tsfuncs_pat_desc.o \
12
+	tsfuncs_pmt.o \
13
+	tsfuncs_nit.o tsfuncs_nit_desc.o \
14
+	tsfuncs_sdt.o tsfuncs_sdt_desc.o \
15
+	tsfuncs_eit.o tsfuncs_eit_desc.o \
16
+	tsfuncs_tdt.o \
17
+	tsfuncs_pes.o tsfuncs_pes_data.o \
18
+	tsfuncs_pes_es.o
19
+PROG = libts.a
20
+
21
+all: $(PROG)
22
+
23
+$(PROG): $(OBJS) tsdata.h
24
+	$(Q)echo "  LINK	$(PROG)"
25
+	$(Q)$(LINK) $@ $(LIBRARY_LINK_OPTS) $(OBJS) 
26
+
27
+%.o: %.c
28
+	$(Q)echo "  CC	libts	$<"
29
+	$(Q)$(CC) $(CFLAGS) -c $<
30
+
31
+clean:
32
+	$(Q)echo "  RM	$(PROG) $(OBJS)"
33
+	$(Q)$(RM) $(PROG) *.o *~
34
+
35
+distclean: clean

+ 25 - 0
log.c View File

@@ -0,0 +1,25 @@
1
+#include <stdio.h>
2
+#include <stdarg.h>
3
+
4
+#include "log.h"
5
+
6
+void ts_LOG_default(const char *msg) {
7
+	fprintf(stdout, "%s", msg);
8
+}
9
+
10
+static void (*ts_LOG_callback)(const char *msg) = ts_LOG_default;
11
+
12
+void ts_LOGf(const char *fmt, ...) {
13
+	char msg[1024];
14
+	va_list args;
15
+	va_start(args, fmt);
16
+	vsnprintf(msg, sizeof(msg)-1, fmt, args);
17
+	va_end(args);
18
+	msg[sizeof(msg)-2] = '\n';
19
+	msg[sizeof(msg)-1] = '\0';
20
+	ts_LOG_callback(msg);
21
+}
22
+
23
+void ts_set_log_func(void (*LOG_func)(const char *msg)) {
24
+	ts_LOG_callback = LOG_func;
25
+}

+ 9 - 0
log.h View File

@@ -0,0 +1,9 @@
1
+#ifndef LIBTS_LOG_H
2
+#define LIBTS_LOG_H
3
+
4
+__attribute__ ((format(printf, 1, 2)))
5
+void ts_LOGf(const char *fmt, ...);
6
+
7
+void ts_set_log_func(void (*LOG_func)(const char *msg));
8
+
9
+#endif

+ 435 - 0
tsdata.h View File

@@ -0,0 +1,435 @@
1
+#ifndef LIBTS_TSDATA_H
2
+#define LIBTS_TSDATA_H
3
+
4
+#include <netdb.h>
5
+#include <time.h>
6
+
7
+#ifndef FREE
8
+	#define FREE(x) if(x) { free(x); x=NULL; }
9
+#endif
10
+
11
+#define TS_PACKET_SIZE       188
12
+#define TS_MAX_PAYLOAD_SIZE  (TS_PACKET_SIZE-4)
13
+
14
+struct ts_header {
15
+	uint8_t		sync_byte;			// Always 0x47
16
+
17
+	uint16_t	tei           : 1,	// Transport Error Indicator (TEI)
18
+				pusi          : 1,	// Payload Unit Start Indicator
19
+				prio          : 1,	// Transport Priority
20
+				pid           : 13;	// PID
21
+
22
+	uint8_t		scramble      : 2,	// 00 - not scrambled, 01 - reserved, 10 - scrambled with even key,  11 - scrambled with odd key
23
+				adapt_field   : 1,
24
+				payload_field : 1,
25
+				continuity    : 4;
26
+
27
+	// The variables bellow this line depends may not exist in a packet
28
+	uint8_t		adapt_len;			// adaptation field length
29
+	uint8_t		adapt_flags;		// adaptation field flags
30
+
31
+	uint8_t		payload_size;		// Payload size inside the packet
32
+	uint8_t		payload_offset;		// Payload offset inside the packet
33
+};
34
+
35
+struct mpeg_audio_header {
36
+	uint32_t	syncword		: 12,
37
+				ID				: 1,
38
+				layer			: 2,
39
+				protection_bit	: 1,
40
+				bitrate_index	: 4,
41
+				sampl_freq		: 2,
42
+				padding_bit		: 1,
43
+				private_bit		: 1,
44
+				mode			: 2,
45
+				mode_extension	: 2,
46
+				copyright		: 1,
47
+				org_home		: 1,
48
+				emphasis		: 2;
49
+
50
+	uint8_t		initialized;
51
+};
52
+
53
+struct ts_pes {
54
+	struct ts_header ts_header;
55
+
56
+	uint32_t	have_pts		: 1,		// Have PTS in the PES (init from PES header)
57
+				have_dts		: 1,		// Have DTS in the PES (init from PES header)
58
+				is_audio		: 1,		// PES carries audio (mpeg2 or AC3) (init from PES stream_id and PMT stream_type and descriptors)
59
+				is_audio_mpeg1	: 1,		// PES carries MP1 audio (init from PMT stream_id)
60
+				is_audio_mpeg1l1: 1,		// PES carries MP1 audio Layer I (init from PMT audio descriptor)
61
+				is_audio_mpeg1l2: 1,		// PES carries MP1 audio Layer II (init from PMT audio descriptor)
62
+				is_audio_mpeg1l3: 1,		// PES carries MP1 audio Layer III (init from PMT audio descriptor)
63
+				is_audio_mpeg2	: 1,		// PES carries MP2 audio (init from PMT stream_id)
64
+				is_audio_aac	: 1,		// PES carries AAC audio (init from PMT stream_id)
65
+				is_audio_ac3	: 1,		// PES carries AC3 audio (init from stream_id and PMT descriptors and elmentary stream)
66
+				is_audio_dts	: 1,		// PES carries DTS audio (init from stream_id and elementary stream)
67
+				is_video		: 1,		// PES carries video (mpeg2 or H.264) (init from PES stream_id)
68
+				is_video_mpeg1	: 1,		// PES carries mpeg1 video (init from PES stream_id)
69
+				is_video_mpeg2	: 1,		// PES carries mpeg2 video (init from PES stream_id)
70
+				is_video_mpeg4	: 1,		// PES carries mpeg4 part 2 video (init from PES stream_id)
71
+				is_video_h264	: 1,		// PES carries H.264 video (init from PES stream_id)
72
+				is_video_avs	: 1,		// PES carries AVS video (init from PES stream_id)
73
+				is_teletext		: 1,		// PES carries teletext (init from PMT descriptors)
74
+				is_subtitle		: 1;		// PES carries subtitles (init from PMT descriptors)
75
+
76
+	uint8_t		stream_id;					// If !0 then the PES has started initializing
77
+	uint16_t	pes_packet_len;				// Allowed to be 0 for video streams
78
+	int			real_pes_packet_len;		// if pes_packet_len is > 0 the this is eq to pes_packet_len
79
+											// if pes_packet_len is = 0 this is set to -1 until very last packet
80
+
81
+	uint8_t		flags_1;					// Bellow flags
82
+	uint8_t		reserved1			: 2,	// Always eq 2 (10 binary)
83
+				scrambling			: 2,
84
+				priority			: 1,
85
+				data_alignment		: 1,
86
+				copyright			: 1,
87
+				original_or_copy	: 1;
88
+
89
+	uint8_t		flags_2;					// Bellow flags
90
+	uint8_t		PTS_flag			: 1,
91
+				DTS_flag			: 1,
92
+				ESCR_flag			: 1,
93
+				ES_rate_flag		: 1,
94
+				trick_mode_flag		: 1,
95
+				add_copy_info_flag	: 1,
96
+				pes_crc_flag		: 1,
97
+				pes_extension_flag	: 1;
98
+
99
+	uint8_t		pes_header_len;
100
+
101
+	uint64_t	PTS;						// if (PTS_flag)
102
+	uint64_t	DTS;						// if (DTS_flag)
103
+	uint64_t	ESCR;						// if (ESCR_flag)
104
+	uint32_t	ES_rate;					// if (ES_rate_flag)
105
+
106
+	uint16_t	trick_mode_control	: 2,	// if (trick_mode_flag)
107
+				field_id			: 2,
108
+				intra_slice_refresh	: 1,
109
+				freq_truncation		: 2,
110
+				rep_ctrl			: 5,
111
+				tm_reserved			: 4;
112
+
113
+	uint8_t		reserved_add		: 1,	// if (add_copy_info_flag)
114
+				add_copy_info		: 7;
115
+
116
+	uint16_t	prev_pes_crc;				// if (pes_crc_flag)
117
+
118
+	// PES extension
119
+	uint8_t		flags_3;					// Bellow flags
120
+	uint8_t		pes_private_data_flag			: 1,
121
+				pack_header_field_flag			: 1,
122
+				program_packet_seq_counter_flag	: 1,
123
+				p_std_buffer_flag				: 1,
124
+				reserved2						: 3,
125
+				pes_extension2_flag				: 1;
126
+
127
+	uint64_t	pes_private_data_1;					// if (pes_private_data_flag)
128
+	uint64_t	pes_private_data_2;					// The whole field is 128 bits
129
+
130
+	uint8_t		pack_header_len;					// if (pack_header_field_flag)
131
+	uint8_t		*pack_header;						// Pointer into *pes_data
132
+
133
+	uint8_t		reserved3					: 1,	// if (program_packet_seq_counter_flag)
134
+				program_packet_seq_counter	: 7;
135
+
136
+	uint8_t		mpeg1_mpeg2_identifier		: 1,
137
+				original_stuff_length		: 6;
138
+
139
+	uint16_t	p_std_reserved				: 2,	// Always 1, if (p_std_buffer_flag)
140
+				p_std_buffer_scale			: 1,
141
+				p_std_buffer_size			: 13;
142
+
143
+	uint16_t	reserved4					: 1,	// if (pes_extension2_flag)
144
+				pes_extension_field_len		: 7;
145
+	uint8_t		*pes_extension2;					// Pointer into *pes_data
146
+
147
+	// Private data
148
+	uint8_t		*pes_data;				// Whole packet is stored here
149
+	uint32_t	pes_data_pos;			// How much data is filled in pes_data
150
+	uint32_t	pes_data_size;			// Total allocated for pes_data
151
+	uint8_t		pes_data_initialized;	// Set to 1 when all of the pes_data is in *pes_data and the parsing can start
152
+
153
+	// More private data
154
+	uint8_t		*es_data;				// Pointer to start of data after PES header, initialized when the packet is fully assembled
155
+	uint32_t	es_data_size;			// Full pes packet length (used for video streams, otherwise equal to pes_packet_len)
156
+	uint8_t		initialized;			// Set to 1 when the packet is fully assembled
157
+
158
+	// Extra data
159
+	struct mpeg_audio_header mpeg_audio_header;
160
+};
161
+
162
+struct pes_entry {
163
+	uint16_t		pid;
164
+	struct ts_pes	*pes;
165
+	struct ts_pes	*pes_next;
166
+};
167
+
168
+struct pes_array {
169
+	int max;
170
+	int cur;
171
+	struct pes_entry **entries;
172
+};
173
+
174
+
175
+struct ts_section_header {
176
+	uint8_t		pointer_field;
177
+
178
+	uint8_t		table_id;
179
+
180
+	uint16_t	section_syntax_indicator: 1,	// Section Syntax Indicator
181
+				private_indicator       : 1,	// Private section indicator
182
+				reserved1               : 2,	// 2 reserved bits
183
+				section_length          : 12;	// Section lenth
184
+
185
+	uint16_t	ts_id_number;					// Transport stream id (in PAT), Program number (in PMT)
186
+
187
+	uint8_t		reserved2              : 2,
188
+				version_number         : 5,
189
+				current_next_indicator : 1;
190
+
191
+	uint8_t		section_number;
192
+	uint8_t		last_section_number;
193
+
194
+	// The variables bellow this line are not in the physical packet
195
+	uint16_t	data_size;						// Section length scaled within one packet
196
+	uint16_t	packet_section_len;				// Section length in the current packet minus - 4 (the CRC)
197
+
198
+	int			section_pos;					// Up to this pos the section data has come
199
+	int			initialized;					// Set to 1 when whole sectino is initialized
200
+
201
+	uint8_t		*section_data;					// The whole section data
202
+	uint8_t		*packet_data;					// TS packet(s) that were used to transfer the table.
203
+
204
+	int			num_packets;					// From how much packets this section is build
205
+};
206
+
207
+struct ts_pat_program {
208
+	uint16_t	program;
209
+	uint16_t	reserved:3,
210
+				pid:13;
211
+};
212
+
213
+struct ts_pat {
214
+	struct ts_header			ts_header;
215
+	struct ts_section_header	*section_header;
216
+
217
+	struct ts_pat_program		**programs;
218
+	uint32_t					CRC;
219
+
220
+	// The variables bellow are nor part of the physical packet
221
+	int							programs_max;	// How much programs are allocated
222
+	int							programs_num;	// How much programs are initialized
223
+	uint8_t						initialized;	// Set to 1 when full table is initialized
224
+};
225
+
226
+struct ts_pmt_stream {
227
+	uint8_t		stream_type;
228
+
229
+	uint16_t	reserved1    : 3,
230
+				pid          : 13;
231
+
232
+	uint16_t	reserved2    : 4,
233
+				ES_info_size : 12;
234
+
235
+	uint8_t		*ES_info;
236
+};
237
+
238
+struct ts_pmt {
239
+	struct ts_header			ts_header;
240
+	struct ts_section_header	*section_header;
241
+
242
+	uint16_t					reserved1         : 3,
243
+								PCR_pid           : 13;
244
+
245
+	uint16_t					reserved2         : 4,
246
+								program_info_size : 12;
247
+	uint8_t						*program_info;
248
+
249
+	struct ts_pmt_stream		**streams;
250
+
251
+	uint32_t					CRC;
252
+
253
+	// The variables bellow are nor part of the physical packet
254
+	int							streams_max;	// How much streams are allocated
255
+	int							streams_num;	// How much streams are initialized
256
+	uint8_t						initialized;	// Set to 1 when full table is initialized
257
+};
258
+
259
+
260
+struct ts_sdt_stream {
261
+	uint16_t	service_id;
262
+
263
+	uint8_t		reserved1                  : 6,
264
+				EIT_schedule_flag          : 1,
265
+				EIT_present_following_flag : 1;
266
+
267
+	uint16_t	running_status             : 3,
268
+				free_CA_mode               : 1,
269
+				descriptor_size            : 12;
270
+
271
+	uint8_t		*descriptor_data;
272
+};
273
+
274
+struct ts_sdt {
275
+	struct ts_header			ts_header;
276
+	struct ts_section_header	*section_header;
277
+
278
+	uint16_t					original_network_id;
279
+	uint8_t						reserved;
280
+
281
+	struct ts_sdt_stream		**streams;
282
+
283
+	uint32_t					CRC;
284
+
285
+	// The variables bellow are nor part of the physical packet
286
+	int							streams_max;	// How much streams are allocated
287
+	int							streams_num;	// How much streams are initialized
288
+	uint8_t						initialized;	// Set to 1 when full table is initialized
289
+};
290
+
291
+
292
+
293
+struct ts_nit_stream {
294
+	uint16_t	transport_stream_id;
295
+	uint16_t	original_network_id;
296
+
297
+	uint16_t	reserved1       : 4,
298
+				descriptor_size : 12;
299
+
300
+	uint8_t		*descriptor_data;
301
+};
302
+
303
+struct ts_nit {
304
+	struct ts_header			ts_header;
305
+	struct ts_section_header	*section_header;
306
+
307
+	uint16_t					reserved1         : 4,
308
+								network_info_size : 12;
309
+
310
+	uint8_t						*network_info;
311
+
312
+	uint16_t					reserved2         : 4,
313
+								ts_loop_size      : 12;
314
+
315
+	struct ts_nit_stream		**streams;
316
+
317
+	uint32_t					CRC;
318
+
319
+	// The variables bellow are nor part of the physical packet
320
+	int							streams_max;	// How much streams are allocated
321
+	int							streams_num;	// How much streams are initialized
322
+	uint8_t						initialized;	// Set to 1 when full NIT table is initialized
323
+};
324
+
325
+
326
+struct ts_eit_stream {
327
+	uint16_t	event_id;
328
+	uint64_t	start_time_mjd	: 16,
329
+				start_time_bcd	: 24,	// Total 40, start_time
330
+				duration_bcd	: 24;
331
+
332
+	uint16_t	running_status	: 3,
333
+				free_CA_mode	: 1,
334
+				descriptor_size	: 12;
335
+
336
+	uint8_t		*descriptor_data;
337
+};
338
+
339
+struct ts_eit {
340
+	struct ts_header			ts_header;
341
+	struct ts_section_header	*section_header;
342
+
343
+	uint16_t					transport_stream_id;
344
+	uint16_t					original_network_id;
345
+	uint8_t						segment_last_section_number;
346
+	uint8_t						last_table_id;
347
+
348
+	struct ts_eit_stream		**streams;
349
+
350
+	uint32_t					CRC;
351
+
352
+	// The variables bellow are nor part of the physical packet
353
+	int							streams_max;	// How much streams are allocated
354
+	int							streams_num;	// How much streams are initialized
355
+	uint8_t						initialized;	// Set to 1 when full eit table is initialized
356
+};
357
+
358
+struct ts_tdt {
359
+	struct ts_header			ts_header;
360
+
361
+	uint8_t		pointer_field;
362
+
363
+	uint8_t		table_id;
364
+
365
+	uint16_t	section_syntax_indicator: 1,	// Section Syntax Indicator
366
+				reserved_1              : 1,	// 1 reserved bit
367
+				reserved_2              : 2,	// 2 reserved bits
368
+				section_length          : 12;	// Section lenth
369
+
370
+	uint16_t	mjd;							// This both are part of one 40 bit field (UTC_time)
371
+	uint32_t	bcd;							// Only 24 bits are used
372
+
373
+	// The below fields are only in TOT packets, table_id 0x73
374
+	uint16_t	reserved_3				: 4,
375
+				descriptors_size        : 12;
376
+	uint8_t		*descriptors;
377
+	uint32_t	CRC;
378
+
379
+	// The variables bellow are nor part of the physical packet
380
+	uint8_t		*packet_data;
381
+	time_t		utc;	// decoded UTC_time
382
+	struct tm	tm;		// decoded UTC_time
383
+
384
+	uint8_t		initialized;
385
+};
386
+
387
+// PMT stream types
388
+enum ts_stream_type {
389
+	STREAM_TYPE_MPEG1_VIDEO			= 0x01, // MPEG-1 video
390
+	STREAM_TYPE_MPEG2_VIDEO			= 0x02,	// H.262 - MPEG-2 video
391
+
392
+	STREAM_TYPE_MPEG1_AUDIO			= 0x03, // MPEG-1 audio
393
+	STREAM_TYPE_MPEG2_AUDIO			= 0x04, // MPEG-2 audio
394
+
395
+	STREAM_TYPE_ADTS_AUDIO			= 0x0F,	// AAC ADTS
396
+	STREAM_TYPE_MPEG4_PART2_VIDEO	= 0x10, // DIVX - MPEG-4 part 2
397
+
398
+	STREAM_TYPE_AVC_VIDEO			= 0x1B,	// H.264 - MPEG-4 part 10
399
+	STREAM_TYPE_AVS_VIDEO			= 0x42,	// Chinese AVS
400
+
401
+	STREAM_TYPE_DOLBY_DVB_AUDIO		= 0x06, // 0x06 - Private stream, look at stream descriptors for AC-3 descriptor
402
+	STREAM_TYPE_DOLBY_ATSC_AUDIO	= 0x81, // 0x81 - Private stream in ATSC (US system, probably we shouldn't care)
403
+};
404
+
405
+// ------------------------------------------------------------
406
+// PES packet stream ids
407
+// See H.222.0 Table 2-17 and Table 2-18
408
+#define STREAM_ID_PROGRAM_STREAM_MAP		0xbc
409
+#define STREAM_ID_PRIVATE_STREAM_1			0xbd
410
+#define STREAM_ID_PADDING_STREAM			0xbe
411
+#define STREAM_ID_PRIVATE_STREAM_2			0xbf
412
+#define STREAM_ID_ECM_STREAM				0xf0
413
+#define STREAM_ID_EMM_STREAM				0xf1
414
+#define STREAM_ID_DSMCC_STREAM				0xf2
415
+#define STREAM_ID_13522_STREAM				0xf3
416
+#define STREAM_ID_H222_A_STREAM				0xf4
417
+#define STREAM_ID_H222_B_STREAM				0xf5
418
+#define STREAM_ID_H222_C_STREAM				0xf6
419
+#define STREAM_ID_H222_D_STREAM				0xf7
420
+#define STREAM_ID_H222_E_STREAM				0xf8
421
+#define STREAM_ID_ANCILLARY_STREAM			0xf9
422
+#define STREAM_ID_PROGRAM_STREAM_DIRECTORY	0xff
423
+
424
+#define IS_AUDIO_STREAM_ID(id)				((id) >= 0xc0 && (id) <= 0xdf)
425
+#define IS_VIDEO_STREAM_ID(id)				((id) >= 0xe0 && (id) <= 0xef)
426
+#define IS_PES_STREAM_SUPPORTED(id)			(!(id == STREAM_ID_PROGRAM_STREAM_MAP       || \
427
+											   id == STREAM_ID_PADDING_STREAM           || \
428
+										       id == STREAM_ID_PRIVATE_STREAM_2         || \
429
+										       id == STREAM_ID_ECM_STREAM               || \
430
+											   id == STREAM_ID_EMM_STREAM               || \
431
+										       id == STREAM_ID_PROGRAM_STREAM_DIRECTORY || \
432
+										       id == STREAM_ID_DSMCC_STREAM             || \
433
+										       id == STREAM_ID_H222_E_STREAM))
434
+
435
+#endif

+ 422 - 0
tsfuncs.c View File

@@ -0,0 +1,422 @@
1
+#include <stdio.h>
2
+#include <unistd.h>
3
+#include <netdb.h>
4
+#include <stdlib.h>
5
+#include <string.h>
6
+#include <ctype.h>
7
+#include <sys/time.h>
8
+
9
+#include "tsfuncs.h"
10
+
11
+void ts_packet_init_null(uint8_t *ts_packet) {
12
+	memset(ts_packet, 0xff, TS_PACKET_SIZE);
13
+	ts_packet[0] = 0x47;
14
+	ts_packet[1] = 0x1f;
15
+	ts_packet[2] = 0xff;
16
+	ts_packet[3] = 0x00;
17
+}
18
+
19
+inline int ts_packet_is_pusi(uint8_t *ts_packet) {
20
+	return (ts_packet[1] &~ 0xbf) >> 6;
21
+}
22
+
23
+inline uint16_t ts_packet_get_pid(uint8_t *ts_packet) {
24
+	return (ts_packet[1] &~ 0xE0) << 8 | ts_packet[2];
25
+}
26
+
27
+inline void ts_packet_set_pid(uint8_t *ts_packet, uint16_t new_pid) {
28
+	ts_packet[1]  = (ts_packet[1] &~ 0x1f) | (new_pid >> 8);	// 111xxxxx xxxxxxxx
29
+	ts_packet[2]  = new_pid &~ 0xff00;
30
+}
31
+
32
+inline uint8_t ts_packet_get_cont(uint8_t *ts_packet) {
33
+	return (ts_packet[3] &~ 0xF0);	// 1111xxxx
34
+}
35
+
36
+inline void ts_packet_set_cont(uint8_t *ts_packet, uint8_t value) {
37
+	// Mask the last 4 bits (continuity), then set the continuity
38
+	ts_packet[3] =  (ts_packet[3] &~ 0x0F) | (value &~ 0xF0);
39
+}
40
+
41
+inline void ts_packet_inc_cont(uint8_t *ts_packet, uint8_t increment) {
42
+	ts_packet_set_cont(ts_packet, ts_packet_get_cont(ts_packet) + increment);
43
+}
44
+
45
+inline int ts_packet_is_scrambled(uint8_t *ts_packet) {
46
+	return (ts_packet[3] >> 6) > 1; // 0 is not scamlbed, 1 is reserved, 2 or 3 mean scrambled
47
+}
48
+
49
+void ts_packet_set_scrambled(uint8_t *ts_packet, enum ts_scrambled_type stype) {
50
+	ts_packet[3] = ts_packet[3] &~ 0xc0; // Mask top two bits (11xxxxxx)
51
+	if (stype == scrambled_with_even_key)
52
+		ts_packet[3] |= 2 << 6;
53
+	if (stype == scrambled_with_odd_key)
54
+		ts_packet[3] |= 3 << 6;
55
+	if (stype == scrambled_reserved)
56
+		ts_packet[3] |= 1 << 6;
57
+}
58
+
59
+uint8_t ts_packet_get_payload_offset(uint8_t *ts_packet) {
60
+	if (ts_packet[0] != 0x47)
61
+		return 0;
62
+
63
+	uint8_t adapt_field   = (ts_packet[3] &~ 0xDF) >> 5; // 11x11111
64
+	uint8_t payload_field = (ts_packet[3] &~ 0xEF) >> 4; // 111x1111
65
+
66
+	if (!adapt_field && !payload_field) // Not allowed
67
+		return 0;
68
+
69
+	if (adapt_field) {
70
+		uint8_t adapt_len = ts_packet[4];
71
+		if (payload_field && adapt_len > 182) // Validity checks
72
+			return 0;
73
+		if (!payload_field && adapt_len > 183)
74
+			return 0;
75
+		if (adapt_len + 1 + 4 >= 188) // adaptation field takes the whole packet
76
+			return 0;
77
+		return 4 + 1 + adapt_len; // ts header + adapt_field_len_byte + adapt_field_len
78
+	} else {
79
+		return 4; // No adaptation, data starts directly after TS header
80
+	}
81
+}
82
+
83
+/*
84
+ * Decode a PTS or DTS value.
85
+ *
86
+ * - `data` is the 5 bytes containing the encoded PTS or DTS value
87
+ * - `required_guard` should be 2 for a PTS alone, 3 for a PTS before
88
+ *   a DTS, or 1 for a DTS after a PTS
89
+ * - `value` is the PTS or DTS value as decoded
90
+ *
91
+ * Returns 0 if the PTS/DTS value is decoded successfully, 1 if an error occurs
92
+ */
93
+int ts_decode_pts_dts(uint8_t *data, int required_guard, uint64_t *value) {
94
+  uint64_t      pts1,pts2,pts3;
95
+  int           marker;
96
+  char         *what;
97
+  int           guard = (data[0] & 0xF0) >> 4;
98
+
99
+  // Rather than try to use casts to make the arithmetic come out right on both
100
+  // Linux-with-gcc (old-style C rules) and Windows-with-VisualC++ (C99 rules),
101
+  // it's simpler just to use intermediates that won't get cast to "int".
102
+  unsigned int  data0 = data[0];
103
+  unsigned int  data1 = data[1];
104
+  unsigned int  data2 = data[2];
105
+  unsigned int  data3 = data[3];
106
+  unsigned int  data4 = data[4];
107
+
108
+  switch (required_guard) {
109
+    case 2:  what = "PTS"; break;  // standalone
110
+    case 3:  what = "PTS"; break;  // before a DTS
111
+    case 1:  what = "DTS"; break;  // always after a PTS
112
+    default: what = "???"; break;
113
+  }
114
+
115
+  if (guard != required_guard)
116
+  {
117
+    ts_LOGf("!!! decode_pts_dts(), Guard bits at start of %s data are %x, not %x\n", what, guard, required_guard);
118
+  }
119
+
120
+  pts1 = (data0 & 0x0E) >> 1;
121
+  marker = data0 & 0x01;
122
+  if (marker != 1)
123
+  {
124
+    ts_LOGf("!!! decode_pts_dts(), First %s marker is not 1\n",what);
125
+    return 0;
126
+  }
127
+
128
+  pts2 = (data1 << 7) | ((data2 & 0xFE) >> 1);
129
+  marker = data2 & 0x01;
130
+  if (marker != 1)
131
+  {
132
+    ts_LOGf("!!! decode_pts_dts(), Second %s marker is not 1\n",what);
133
+    return 0;
134
+  }
135
+
136
+  pts3 = (data3 << 7) | ((data4 & 0xFE) >> 1);
137
+  marker = data4 & 0x01;
138
+  if (marker != 1)
139
+  {
140
+    ts_LOGf("!!! decode_pts_dts(), Third %s marker is not 1\n",what);
141
+    return 0;
142
+  }
143
+
144
+  *value = (pts1 << 30) | (pts2 << 15) | pts3;
145
+  return 1;
146
+}
147
+
148
+/*
149
+ * Encode a PTS or DTS.
150
+ *
151
+ * - `data` is the array of 5 bytes into which to encode the PTS/DTS
152
+ * - `guard_bits` are the required guard bits: 2 for a PTS alone, 3 for
153
+ *   a PTS before a DTS, or 1 for a DTS after a PTS
154
+ * - `value` is the PTS or DTS value to be encoded
155
+ */
156
+void ts_encode_pts_dts(uint8_t *data, int guard_bits, uint64_t value) {
157
+  int   pts1,pts2,pts3;
158
+
159
+#define MAX_PTS_VALUE 0x1FFFFFFFFLL
160
+
161
+  if (value > MAX_PTS_VALUE)
162
+  {
163
+    char        *what;
164
+    uint64_t     temp = value;
165
+    while (temp > MAX_PTS_VALUE)
166
+      temp -= MAX_PTS_VALUE;
167
+    switch (guard_bits)
168
+    {
169
+    case 2:  what = "PTS alone"; break;
170
+    case 3:  what = "PTS before DTS"; break;
171
+    case 1:  what = "DTS after PTS"; break;
172
+    default: what = "PTS/DTS/???"; break;
173
+    }
174
+    ts_LOGf("!!! value %llu for %s is more than %llu - reduced to %llu\n",value,what,MAX_PTS_VALUE,temp);
175
+    value = temp;
176
+  }
177
+
178
+  pts1 = (int)((value >> 30) & 0x07);
179
+  pts2 = (int)((value >> 15) & 0x7FFF);
180
+  pts3 = (int)( value        & 0x7FFF);
181
+
182
+  data[0] =  (guard_bits << 4) | (pts1 << 1) | 0x01;
183
+  data[1] =  (pts2 & 0x7F80) >> 7;
184
+  data[2] = ((pts2 & 0x007F) << 1) | 0x01;
185
+  data[3] =  (pts3 & 0x7F80) >> 7;
186
+  data[4] = ((pts3 & 0x007F) << 1) | 0x01;
187
+}
188
+
189
+// Return 0 on failure
190
+// Return payload_ofs on success
191
+int ts_packet_has_pes(uint8_t *ts_packet, uint16_t *pes_packet_len) {
192
+	uint8_t payload_ofs;
193
+	uint8_t *payload;
194
+
195
+	if (!ts_packet_is_pusi(ts_packet))
196
+		goto ERR;
197
+
198
+	payload_ofs = ts_packet_get_payload_offset(ts_packet);
199
+	if (!payload_ofs)
200
+		goto ERR;
201
+
202
+	if (payload_ofs + 6 + 2 >= 188) // 6 bytes pes header, 2 bytes pes flags
203
+		goto ERR;
204
+
205
+	payload = ts_packet + payload_ofs;
206
+	if (payload[0] == 0x00 && payload[1] == 0x00 && payload[2] == 0x01) { // pes_start_code_prefix
207
+		uint8_t stream_id  = payload[3];
208
+		if (pes_packet_len)
209
+			*pes_packet_len = (payload[4] << 8) | payload[5];
210
+		// We do not handle this streams...
211
+		if (!IS_PES_STREAM_SUPPORTED(stream_id))
212
+			goto ERR;
213
+		return payload_ofs;
214
+	}
215
+
216
+ERR:
217
+	return 0;
218
+}
219
+
220
+int ts_packet_has_pts_dts(uint8_t *ts_packet, uint64_t *pts, uint64_t *dts) {
221
+	*pts = NO_PTS;
222
+	*dts = NO_DTS;
223
+
224
+	uint8_t payload_ofs = ts_packet_has_pes(ts_packet, NULL);
225
+	if (!payload_ofs)
226
+		goto ERR;
227
+
228
+	uint8_t *data = ts_packet + payload_ofs;
229
+	uint8_t *data_end = ts_packet + 188;
230
+	if ((data[6] &~ 0x3f) != 0x80) // 10xxxxxx (first two bits must be 10 eq 0x80
231
+		goto ERR;
232
+
233
+	if (data + 7 >= data_end) goto ERR;
234
+	uint8_t pts_flag = bit_on(data[7], bit_8); // PES flags 2
235
+	uint8_t dts_flag = bit_on(data[7], bit_7); // PES flags 2
236
+
237
+	if (!pts_flag && dts_flag)	// Invalid, can't have only DTS flag
238
+		return 0;
239
+
240
+	if (pts_flag && !dts_flag) {
241
+		if (data + 14 >= data_end) goto ERR;
242
+		if (!ts_decode_pts_dts(&data[9], 2, pts))
243
+			goto ERR;
244
+	} else if (pts_flag && dts_flag) {
245
+		if (data + 19 >= data_end) goto ERR;
246
+		if (!ts_decode_pts_dts(&data[9], 3, pts))
247
+			goto ERR;
248
+		if (!ts_decode_pts_dts(&data[14], 1, dts))
249
+			goto ERR;
250
+	}
251
+	return 1;
252
+
253
+ERR:
254
+	return 0;
255
+}
256
+
257
+void ts_packet_change_pts(uint8_t *ts_packet, uint64_t pts) {
258
+	uint8_t payload_offset = ts_packet_get_payload_offset(ts_packet);
259
+	if (!payload_offset)
260
+		return;
261
+	uint8_t *data = ts_packet + payload_offset;
262
+	ts_encode_pts_dts(&data[9], 2, pts);
263
+}
264
+
265
+void ts_packet_change_pts_dts(uint8_t *ts_packet, uint64_t pts, uint64_t dts) {
266
+	uint8_t payload_offset = ts_packet_get_payload_offset(ts_packet);
267
+	if (!payload_offset)
268
+		return;
269
+	uint8_t *data = ts_packet + payload_offset;
270
+	ts_encode_pts_dts(&data[9],  3, pts);
271
+	ts_encode_pts_dts(&data[14], 1, dts);
272
+}
273
+
274
+
275
+int ts_packet_has_pcr(uint8_t *ts_packet) {
276
+	if (ts_packet[0] == 0x47) { // TS packet
277
+		if (bit_on(ts_packet[3], bit_6)) { // Packet have adaptation field
278
+			if (ts_packet[4] > 6) { // Adaptation field length is > 6
279
+				if (bit_on(ts_packet[5], bit_5)) { // The is PCR field
280
+					return 1;
281
+				} else {
282
+//					ts_LOGf("!no PCR field\n");
283
+				}
284
+			} else {
285
+//				ts_LOGf("!not enough adaptation len (%d), need at least 7\n", ts_packet[4]);
286
+			}
287
+		} else {
288
+//			ts_LOGf("!no adaptation field\n");
289
+		}
290
+	} else {
291
+//		ts_LOGf("!no ts packet start (0x%02x) need 0x47\n", ts_packet[0]);
292
+	}
293
+	return 0;
294
+}
295
+
296
+uint64_t ts_packet_get_pcr_ex(uint8_t *ts_packet, uint64_t *pcr_base, uint16_t *pcr_ext) {
297
+	uint8_t *data = ts_packet + 6; // Offset in TS packet
298
+	*pcr_base  = (uint64_t)data[0] << 25;
299
+	*pcr_base += (uint64_t)data[1] << 17;
300
+	*pcr_base += (uint64_t)data[2] << 9;
301
+	*pcr_base += (uint64_t)data[3] << 1;
302
+	*pcr_base += (uint64_t)data[4] >> 7;
303
+	*pcr_ext   = ((uint16_t)data[4] & 0x01) << 8;
304
+	*pcr_ext  += (uint16_t)data[5];
305
+	//ts_LOGf("get pcr_base=%10llu pcr_ext=%4u pcr=%llu\n", *pcr_base, *pcr_ext, *pcr_base * 300ll + *pcr_ext);
306
+	return *pcr_base * 300ll + *pcr_ext;
307
+}
308
+
309
+uint64_t ts_packet_get_pcr(uint8_t *ts_packet) {
310
+	uint64_t pcr_base;
311
+	uint16_t pcr_ext;
312
+	return ts_packet_get_pcr_ex(ts_packet, &pcr_base, &pcr_ext);
313
+}
314
+
315
+
316
+void ts_packet_set_pcr_ex(uint8_t *ts_packet, uint64_t pcr_base, uint16_t pcr_ext) {
317
+	//ts_LOGf("set pcr_base=%10llu pcr_ext=%4u pcr=%llu\n", pcr_base, pcr_ext, pcr);
318
+	// 6 is the PCR offset in ts_packet (4 bytes header, 1 byte adapt field len)
319
+	ts_packet[6 + 0] = (pcr_base >> 25) & 0xFF;
320
+	ts_packet[6 + 1] = (pcr_base >> 17) & 0xFF;
321
+	ts_packet[6 + 2] = (pcr_base >> 9)  & 0xFF;
322
+	ts_packet[6 + 3] = (pcr_base >> 1)  & 0xFF;
323
+	ts_packet[6 + 4] = 0x7e | ((pcr_ext >> 8) & 0x01) | ((pcr_base & 0x01) <<7 ); // 0x7e == 6 reserved bits
324
+	ts_packet[6 + 5] = pcr_ext & 0xFF;
325
+}
326
+
327
+void ts_packet_set_pcr(uint8_t *ts_packet, uint64_t pcr) {
328
+	uint64_t pcr_base = pcr / 300;
329
+	uint16_t pcr_ext = pcr % 300;
330
+	ts_packet_set_pcr_ex(ts_packet, pcr_base, pcr_ext);
331
+}
332
+
333
+uint8_t *ts_packet_header_parse(uint8_t *ts_packet, struct ts_header *ts_header) {
334
+	if (ts_packet[0] != 0x47) {
335
+		// ts_LOGf("*** TS packet do not start with sync byte 0x47 but with 0x%02x\n", ts_packet[0]);
336
+		goto return_error;
337
+	}
338
+
339
+	ts_header->tei  = (ts_packet[1] &~ 0x7f) >> 7; // x1111111
340
+	ts_header->pusi = (ts_packet[1] &~ 0xbf) >> 6; // 1x111111
341
+	ts_header->prio = (ts_packet[1] &~ 0xdf) >> 5; // 11x11111
342
+	ts_header->pid  = (ts_packet[1] &~ 0xE0) << 8 | ts_packet[2]; // 111xxxxx xxxxxxxx
343
+
344
+	ts_header->scramble      = (ts_packet[3] &~ 0x3F) >> 6; // xx111111
345
+	ts_header->adapt_field   = (ts_packet[3] &~ 0xDF) >> 5; // 11x11111
346
+	ts_header->payload_field = (ts_packet[3] &~ 0xEF) >> 4; // 111x1111
347
+	ts_header->continuity    = (ts_packet[3] &~ 0xF0);      // 1111xxxx
348
+
349
+	if (!ts_header->adapt_field) {
350
+		ts_header->adapt_len   = 0;
351
+		ts_header->adapt_flags = 0;
352
+		ts_header->payload_offset = 4;
353
+	} else {
354
+		ts_header->adapt_len = ts_packet[4];
355
+		if (ts_header->adapt_len) {
356
+			ts_header->adapt_flags = ts_packet[5];
357
+		}
358
+		ts_header->payload_offset = 5 + ts_header->adapt_len; // 2 bytes see above
359
+	}
360
+
361
+	if (!ts_header->adapt_field && !ts_header->payload_field) // Not allowed
362
+		goto return_error;
363
+
364
+	if (!ts_header->payload_field)
365
+		return NULL;
366
+
367
+	if (ts_header->payload_field && ts_header->adapt_len > 182) // Validity checks
368
+		goto return_error;
369
+	if (!ts_header->payload_field && ts_header->adapt_len > 183)
370
+		goto return_error;
371
+
372
+	if (ts_header->payload_offset > TS_MAX_PAYLOAD_SIZE) // Validity check
373
+		goto return_error;
374
+
375
+	ts_header->payload_size = TS_PACKET_SIZE - ts_header->payload_offset;
376
+
377
+	return ts_packet + ts_header->payload_offset;
378
+
379
+return_error:
380
+	memset(ts_header, 0, sizeof(struct ts_header));
381
+	return NULL;
382
+}
383
+
384
+void ts_packet_header_generate(uint8_t *ts_packet, struct ts_header *ts_header) {
385
+	memset(ts_packet, 0xFF, TS_PACKET_SIZE);
386
+	ts_packet[0]  = 0x47;
387
+
388
+	ts_packet[1]  = 0;
389
+	ts_packet[1]  = ts_header->tei  << 7;			// x1111111
390
+	ts_packet[1] |= ts_header->pusi << 6;			// 1x111111
391
+	ts_packet[1] |= ts_header->prio << 5;			// 11x11111
392
+	ts_packet[1] |= ts_header->pid >> 8;			// 111xxxxx xxxxxxxx
393
+	ts_packet[2]  = ts_header->pid &~ 0xff00;
394
+
395
+	ts_packet[3]  = 0;
396
+	ts_packet[3]  = ts_header->scramble << 6;		// xx111111
397
+	ts_packet[3] |= ts_header->adapt_field << 5;	// 11x11111
398
+	ts_packet[3] |= ts_header->payload_field << 4;	// 111x1111
399
+	ts_packet[3] |= ts_header->continuity;			// 1111xxxx
400
+
401
+	if (ts_header->adapt_field) {
402
+		ts_packet[4] = ts_header->adapt_len;
403
+		ts_packet[5] = ts_header->adapt_flags;
404
+	}
405
+}
406
+
407
+void ts_packet_header_dump(struct ts_header *ts_header) {
408
+	ts_LOGf("*** tei:%d pusi:%d prio:%d pid:%04x (%d) scramble:%d adapt:%d payload:%d adapt_len:%d adapt_flags:%d | pofs:%d plen:%d\n",
409
+		ts_header->tei,
410
+		ts_header->pusi,
411
+		ts_header->prio,
412
+		ts_header->pid,
413
+		ts_header->pid,
414
+		ts_header->scramble,
415
+		ts_header->adapt_field,
416
+		ts_header->payload_field,
417
+		ts_header->adapt_len,
418
+		ts_header->adapt_flags,
419
+		ts_header->payload_offset,
420
+		ts_header->payload_size
421
+	);
422
+}

+ 238 - 0
tsfuncs.h View File

@@ -0,0 +1,238 @@
1
+#ifndef LIBTS_TSFUNCS_H
2
+#define LIBTS_TSFUNCS_H
3
+
4
+#include <time.h>
5
+#include <netdb.h>
6
+
7
+#include "tsdata.h"
8
+
9
+#include "log.h"
10
+
11
+// Usage bit_on(0xff, 0x02)
12
+#define bit_on(__bit, __mask) ((__bit & __mask) ? 1 : 0)
13
+
14
+#define bit_1 (0x01)
15
+#define bit_2 (0x02)
16
+#define bit_3 (0x04)
17
+#define bit_4 (0x08)
18
+#define bit_5 (0x10)
19
+#define bit_6 (0x20)
20
+#define bit_7 (0x40)
21
+#define bit_8 (0x80)
22
+
23
+
24
+#define NO_PCR (-1ull)
25
+#define NO_PCR_BASE (-1ull)
26
+#define NO_PCR_EXT  (0xffff)
27
+#define NO_PCR (-1ull)
28
+#define NO_PTS (-1ull)
29
+#define NO_DTS (-1ull)
30
+
31
+enum ts_scrambled_type {
32
+	not_scrambled           = 0x00,
33
+	scrambled_reserved      = 0x01,
34
+	scrambled_with_odd_key  = 0x02,
35
+	scrambled_with_even_key = 0x03
36
+};
37
+
38
+// Packet manipulation
39
+void            ts_packet_init_null (uint8_t *ts_packet);
40
+
41
+int             ts_packet_is_pusi   (uint8_t *ts_packet);
42
+
43
+uint16_t        ts_packet_get_pid   (uint8_t *ts_packet);
44
+void            ts_packet_set_pid   (uint8_t *ts_packet, uint16_t new_pid);
45
+
46
+uint8_t         ts_packet_get_cont  (uint8_t *ts_packet);
47
+void            ts_packet_set_cont  (uint8_t *ts_packet, uint8_t value);
48
+void            ts_packet_inc_cont  (uint8_t *ts_packet, uint8_t increment);
49
+
50
+uint8_t         ts_packet_get_payload_offset(uint8_t *ts_packet);
51
+
52
+int             ts_packet_is_scrambled(uint8_t *ts_packet);
53
+void            ts_packet_set_scrambled(uint8_t *ts_packet, enum ts_scrambled_type stype);
54
+
55
+int				ts_packet_has_pcr		(uint8_t *ts_packet);
56
+uint64_t		ts_packet_get_pcr_ex	(uint8_t *ts_packet, uint64_t *pcr_base, uint16_t *pcr_ext);
57
+uint64_t		ts_packet_get_pcr		(uint8_t *ts_packet);
58
+void			ts_packet_set_pcr_ex	(uint8_t *ts_packet, uint64_t pcr_base, uint16_t pcr_ext);
59
+void			ts_packet_set_pcr		(uint8_t *ts_packet, uint64_t pcr);
60
+
61
+void			ts_encode_pts_dts		(uint8_t *data, int guard_bits, uint64_t value);
62
+int				ts_decode_pts_dts		(uint8_t *data, int required_guard, uint64_t *value);
63
+
64
+int				ts_packet_has_pes		(uint8_t *ts_packet, uint16_t *pes_packet_len);
65
+int				ts_packet_has_pts_dts	(uint8_t *ts_packet, uint64_t *pts, uint64_t *dts);
66
+
67
+void			ts_packet_change_pts		(uint8_t *ts_packet, uint64_t pts);
68
+void			ts_packet_change_pts_dts	(uint8_t *ts_packet, uint64_t pts, uint64_t dts);
69
+
70
+// TS packet headers
71
+uint8_t *       ts_packet_header_parse    (uint8_t *ts_packet, struct ts_header *ts_header);
72
+void            ts_packet_header_generate (uint8_t *ts_packet, struct ts_header *ts_header);
73
+void            ts_packet_header_dump     (struct ts_header *ts_header);
74
+
75
+// Sections
76
+uint8_t *					ts_section_header_parse		(uint8_t *ts_packet, struct ts_header *ts_header, struct ts_section_header *ts_section_header);
77
+void						ts_section_header_generate	(uint8_t *ts_packet, struct ts_section_header *ts_section_header, uint8_t start);
78
+void						ts_section_header_dump		(struct ts_section_header *t);
79
+
80
+uint8_t *					ts_section_data_alloc_section	();
81
+uint8_t *					ts_section_data_alloc_packet	();
82
+
83
+struct ts_section_header *	ts_section_data_alloc			();
84
+void						ts_section_data_free			(struct ts_section_header **ts_section_header);
85
+
86
+void						ts_section_add_packet		(struct ts_section_header *sec, struct ts_header *ts_header, uint8_t *ts_packet);
87
+
88
+uint32_t					ts_section_data_calculate_crc	(uint8_t *section_data, int section_data_size);
89
+void						ts_section_data_gen_ts_packets	(struct ts_header *ts_header, uint8_t *section_data, int section_data_sz, uint8_t pointer_field, uint8_t **packets, int *num_packets);
90
+
91
+
92
+// PAT
93
+struct ts_pat *	ts_pat_alloc		();
94
+struct ts_pat * ts_pat_alloc_init	(uint16_t transport_stream_id);
95
+struct ts_pat *	ts_pat_push_packet	(struct ts_pat *pat, uint8_t *ts_packet);
96
+void            ts_pat_free			(struct ts_pat **pat);
97
+int				ts_pat_parse		(struct ts_pat *pat);
98
+void            ts_pat_dump			(struct ts_pat *pat);
99
+void			ts_pat_generate		(struct ts_pat *pat, uint8_t **ts_packets, int *num_packets);
100
+
101
+struct ts_pat *	ts_pat_copy					(struct ts_pat *pat);
102
+void			ts_pat_regenerate_packets	(struct ts_pat *pat);
103
+
104
+int             ts_pat_add_program	(struct ts_pat *pat, uint16_t program, uint16_t pat_pid);
105
+int             ts_pat_del_program	(struct ts_pat *pat, uint16_t program);
106
+
107
+int				ts_pat_is_same		(struct ts_pat *pat1, struct ts_pat *pat2);
108
+
109
+
110
+// PMT
111
+struct ts_pmt *	ts_pmt_alloc		();
112
+struct ts_pmt * ts_pmt_alloc_init	(uint16_t org_network_id, uint16_t transport_stream_id);
113
+struct ts_pmt *	ts_pmt_push_packet	(struct ts_pmt *pmt, uint8_t *ts_packet, uint16_t pmt_pid);
114
+void            ts_pmt_free			(struct ts_pmt **pmt);
115
+int				ts_pmt_parse		(struct ts_pmt *pmt);
116
+void            ts_pmt_dump			(struct ts_pmt *pmt);
117
+void			ts_pmt_generate		(struct ts_pmt *pmt, uint8_t **ts_packets, int *num_packets);
118
+
119
+struct ts_pmt *	ts_pmt_copy					(struct ts_pmt *pmt);
120
+void			ts_pmt_regenerate_packets	(struct ts_pmt *pmt);
121
+
122
+int				ts_pmt_is_same		(struct ts_pmt *pmt1, struct ts_pmt *pmt2);
123
+
124
+// NIT
125
+struct ts_nit * ts_nit_alloc		();
126
+struct ts_nit * ts_nit_alloc_init	(uint16_t network_id);
127
+struct ts_nit *	ts_nit_push_packet	(struct ts_nit *nit, uint8_t *ts_packet);
128
+void			ts_nit_free			(struct ts_nit **nit);
129
+int				ts_nit_parse		(struct ts_nit *nit);
130
+void			ts_nit_dump			(struct ts_nit *nit);
131
+void			ts_nit_generate		(struct ts_nit *nit, uint8_t **ts_packets, int *num_packets);
132
+
133
+int				ts_nit_add_network_name_descriptor			(struct ts_nit *nit, char *network_name);
134
+int				ts_nit_add_frequency_list_descriptor_cable	(struct ts_nit *nit, uint16_t ts_id, uint16_t org_net_id, uint32_t *freqs, uint8_t num_freqs);
135
+int				ts_nit_add_cable_delivery_descriptor		(struct ts_nit *nit, uint16_t ts_id, uint16_t org_net_id, uint32_t freq, uint8_t modulation, uint32_t symbol_rate);
136
+int				ts_nit_add_service_list_descriptor			(struct ts_nit *nit, uint16_t ts_id, uint16_t org_net_id, uint32_t *services, uint8_t num_services);
137
+
138
+// SDT
139
+struct ts_sdt *	ts_sdt_alloc		();
140
+struct ts_sdt * ts_sdt_alloc_init	(uint16_t org_network_id, uint16_t transport_stream_id);
141
+struct ts_sdt *	ts_sdt_push_packet	(struct ts_sdt *sdt, uint8_t *ts_packet);
142
+void            ts_sdt_free			(struct ts_sdt **sdt);
143
+int				ts_sdt_parse		(struct ts_sdt *sdt);
144
+void            ts_sdt_dump			(struct ts_sdt *sdt);
145
+void			ts_sdt_generate		(struct ts_sdt *sdt, uint8_t **ts_packets, int *num_packets);
146
+
147
+int             ts_sdt_add_service_descriptor(struct ts_sdt *sdt, uint16_t service_id, uint8_t video, char *provider_name, char *service_name);
148
+
149
+// EIT
150
+struct ts_eit * ts_eit_alloc				();
151
+struct ts_eit *	ts_eit_alloc_init			(uint16_t service_id, uint16_t transport_stream_id, uint16_t org_network_id, uint8_t table_id, uint8_t sec_number, uint8_t last_sec_number);
152
+struct ts_eit *	ts_eit_alloc_init_pf		(uint16_t service_id, uint16_t transport_stream_id, uint16_t org_network_id, uint8_t sec_number, uint8_t last_sec_number);	// Shortcut using table_id 0x4e
153
+struct ts_eit *	ts_eit_alloc_init_schedule	(uint16_t service_id, uint16_t transport_stream_id, uint16_t org_network_id, uint8_t sec_number, uint8_t last_sec_number);	// Shortcut using table_id 0x50
154
+
155
+struct ts_eit *	ts_eit_push_packet	(struct ts_eit *eit, uint8_t *ts_packet);
156
+
157
+void			ts_eit_free			(struct ts_eit **eit);
158
+int				ts_eit_parse		(struct ts_eit *eit);
159
+void			ts_eit_dump			(struct ts_eit *eit);
160
+void			ts_eit_generate		(struct ts_eit *eit, uint8_t **ts_packets, int *num_packets);
161
+
162
+struct ts_eit *	ts_eit_copy					(struct ts_eit *eit);
163
+void			ts_eit_regenerate_packets	(struct ts_eit *eit);
164
+
165
+int				ts_eit_add_short_event_descriptor	(struct ts_eit *eit, uint16_t event_id, uint8_t running, time_t start_time, int duration_sec, char *event_name, char *event_short_descr);
166
+int				ts_eit_add_extended_event_descriptor(struct ts_eit *eit, uint16_t event_id, uint8_t running, time_t start_time, int duration_sec, char *text);
167
+
168
+// TDT
169
+struct ts_tdt *	ts_tdt_alloc_init	(time_t ts);
170
+struct ts_tdt *	ts_tot_alloc_init	(time_t ts);
171
+void			ts_tdt_free			(struct ts_tdt **tdt);
172
+
173
+int				ts_tdt_parse		(struct ts_tdt *tdt, uint8_t *ts_packet);
174
+void			ts_tdt_generate		(struct ts_tdt *tdt, uint8_t *ts_packet);
175
+void			ts_tdt_dump			(struct ts_tdt *tdt);
176
+
177
+void			ts_tdt_set_time		(struct ts_tdt *tdt, time_t ts);
178
+
179
+void			ts_tot_set_localtime_offset			(struct ts_tdt *tdt, time_t now, time_t change_time, uint8_t polarity, uint16_t ofs, uint16_t ofs_next);
180
+void			ts_tot_set_localtime_offset_sofia	(struct ts_tdt *tdt);
181
+
182
+// Time
183
+uint32_t		ts_time_encode_bcd	(int duration_sec);
184
+void			ts_time_decode_bcd	(int duration_bcd, int *duration_sec, int *hour, int *min, int *sec);
185
+
186
+void			ts_time_encode_mjd	(uint16_t *mjd, uint32_t *bcd, time_t *ts, struct tm *tm);
187
+time_t			ts_time_decode_mjd	(uint16_t mjd, uint32_t bcd, struct tm *tm);
188
+
189
+// Descriptors
190
+void            ts_descriptor_dump      (uint8_t *desc_data, int desc_data_len);
191
+int             ts_is_stream_type_video (uint8_t stream_type);
192
+int             ts_is_stream_type_ac3   (uint8_t stream_type);
193
+int             ts_is_stream_type_audio (uint8_t stream_type);
194
+char *          h222_stream_type_desc   (uint8_t stream_type);
195
+char *			h222_stream_id_desc		(uint8_t stream_id);
196
+
197
+// PES
198
+struct ts_pes *		ts_pes_alloc			();
199
+void				ts_pes_free				(struct ts_pes **pes);
200
+struct ts_pes *		ts_pes_reset			(struct ts_pes *pes);
201
+
202
+void				ts_pes_fill_type		(struct ts_pes *pes, struct ts_pmt *pmt, uint16_t pid);
203
+int					ts_pes_is_finished		(struct ts_pes *pes, uint8_t *ts_packet);
204
+struct ts_pes *		ts_pes_push_packet		(struct ts_pes *pes, uint8_t *ts_packet, struct ts_pmt *pmt, uint16_t pid);
205
+
206
+int					ts_pes_parse			(struct ts_pes *pes);
207
+void				ts_pes_dump				(struct ts_pes *pes);
208
+
209
+struct pes_array *		pes_array_alloc			();
210
+void					pes_array_dump			(struct pes_array *pa);
211
+void					pes_array_free			(struct pes_array **ppa);
212
+
213
+struct pes_entry *		pes_array_push_packet	(struct pes_array *pa, uint16_t pid, struct ts_pat *pat, struct ts_pmt *pmt, uint8_t *ts_packet);
214
+
215
+// ES functions
216
+int		ts_pes_es_mpeg_audio_header_parse		(struct mpeg_audio_header *mpghdr, uint8_t *data, int datasz);
217
+void	ts_pes_es_mpeg_audio_header_dump		(struct mpeg_audio_header *mpghdr);
218
+void	ts_pes_es_parse							(struct ts_pes *pes);
219
+void	ts_pes_es_dump							(struct ts_pes *pes);
220
+
221
+
222
+// CRC
223
+uint32_t        ts_crc32      (uint8_t *data, int data_size);
224
+
225
+// Misc
226
+int				dec2bcd						(int dec);
227
+int				bcd2dec						(int bcd);
228
+void			ts_compare_data   			(char *prefix, uint8_t *a, uint8_t *b, int size);
229
+char *			ts_hex_dump      			(uint8_t *d, int size);
230
+void			ts_print_bytes				(char *prefix, uint8_t *d, int size);
231
+char *			init_dvb_string_utf8		(char *text);
232
+char *			init_dvb_string_iso_8859_5	(char *text);
233
+int				ts_is_psi_pid				(uint16_t pid, struct ts_pat *pat);
234
+
235
+// Shortcuts
236
+int parse_tdt   (uint8_t *ts_packet, int dump);
237
+
238
+#endif

+ 40 - 0
tsfuncs_crc.c View File

@@ -0,0 +1,40 @@
1
+#include <netdb.h>
2
+
3
+#include "tsfuncs.h"
4
+
5
+#define CRC32_POLY 0x04C11DB7L
6
+
7
+static int crc_table_initialized = 0;
8
+static uint32_t crc32_table[256];
9
+
10
+void ts_crc32_init() {
11
+	int i, j;
12
+	uint32_t crc;
13
+	if (crc_table_initialized)
14
+		return;
15
+	crc_table_initialized = 1;
16
+	for (i=0; i<256; i++) {
17
+		crc = i << 24;
18
+		for (j=0; j<8; j++) {
19
+			if (crc & 0x80000000L)
20
+				crc = (crc << 1) ^ CRC32_POLY;
21
+			else
22
+				crc = (crc << 1);
23
+		}
24
+		crc32_table[i] = crc;
25
+	}
26
+	crc_table_initialized = 1;
27
+}
28
+
29
+uint32_t ts_crc32(uint8_t *data, int data_size) {
30
+	int i, j;
31
+	uint32_t crc = 0xffffffff;
32
+	if (!crc_table_initialized) {
33
+		ts_crc32_init();
34
+	}
35
+	for (j=0; j<data_size; j++) {
36
+		i = ((crc >> 24) ^ *data++) & 0xff;
37
+		crc = (crc << 8) ^ crc32_table[i];
38
+	}
39
+	return crc;
40
+}

+ 484 - 0
tsfuncs_descriptors.c View File

@@ -0,0 +1,484 @@
1
+#include <stdio.h>
2
+#include <unistd.h>
3
+#include <netdb.h>
4
+#include <stdlib.h>
5
+#include <string.h>
6
+#include <ctype.h>
7
+#include <netdb.h>
8
+
9
+#include "tsfuncs.h"
10
+
11
+static void dvb_print_string(char *pad, char *prefix, uint8_t *input, int text_length) {
12
+	if (text_length < 0) {
13
+		ts_LOGf("%s  !!! %s text_length < 0, %d\n", pad, prefix, text_length);
14
+		return;
15
+	}
16
+	if (text_length == 0) {
17
+		ts_LOGf("%s  %s \"\" (size: %d)\n", pad, prefix, text_length);
18
+		return;
19
+	}
20
+	char *text = calloc(1, text_length + 1);
21
+	memcpy(text, input, text_length);
22
+	if (text[0] < 32)
23
+		ts_LOGf("%s  %s \"%s\" (charset: 0x%02x size: %d)\n", pad, prefix, text+1, text[0], text_length-1);
24
+	else
25
+		ts_LOGf("%s  %s \"%s\" (size: %d)\n", pad, prefix, text, text_length);
26
+	free(text);
27
+}
28
+
29
+void ts_descriptor_dump(uint8_t *desc_data, int desc_data_len) {
30
+	char *pad  = "        * ";
31
+	uint8_t *data = desc_data;
32
+	int data_len = desc_data_len;
33
+	while (data_len >= 2) {
34
+		int i;
35
+		uint32_t temp_u;
36
+
37
+		uint8_t tag         = data[0];
38
+		uint8_t this_length = data[1];
39
+
40
+//		ts_LOGf("%sDescriptor tag: 0x%02x (%d) size: %d\n", padA, tag, tag, this_length);
41
+
42
+		data     += 2;
43
+		data_len -= 2;
44
+
45
+		if (this_length > data_len) {
46
+			// Not much we can do - try giving up?
47
+			ts_LOGf("%s!!! Descriptor 0x%02x says length %d, but only %d bytes left\n", pad, tag, this_length, data_len);
48
+			return;
49
+		}
50
+
51
+		switch (tag) {
52
+			case  2: { // Video stream descriptor
53
+				char *dump = ts_hex_dump(data, this_length);
54
+				ts_LOGf("%sTag 0x%02x (%02d), sz: %d, Video stream descriptor: %s\n", pad, tag, tag, this_length, dump);
55
+				free(dump);
56
+				struct {
57
+					uint8_t multiple_frame_rate_flag     : 1,
58
+					        frame_rate_code              : 4,
59
+					        mpeg1_only_flag              : 1,
60
+					        constraint_parameter_flag    : 1,
61
+					        still_picture_flag           : 1;
62
+					uint8_t profile_and_level_indication;
63
+					uint8_t chroma_format                : 2,
64
+					        frame_rate_extension_flag    : 1,
65
+					        reserved                     : 5;
66
+					uint8_t escape:1, profile:3, level:4;
67
+				} vs;
68
+				if (this_length >= 2) {
69
+					vs.multiple_frame_rate_flag     = bit_on(data[0], bit_8);
70
+					vs.frame_rate_code              = (data[0] &~ 0x80) >> 3; // 1xxxx111
71
+					vs.mpeg1_only_flag              = bit_on(data[0], bit_3);
72
+					vs.constraint_parameter_flag    = bit_on(data[0], bit_2);
73
+					vs.still_picture_flag           = bit_on(data[0], bit_1);
74
+					ts_LOGf("%s  - multiple_frame_rate_flag     : %d\n", pad, vs.multiple_frame_rate_flag);
75
+					ts_LOGf("%s  - frame_rate_code              : %d (%s)\n", pad, vs.frame_rate_code,
76
+						vs.frame_rate_code == 0 ? "forbidden" :
77
+						vs.frame_rate_code == 1 ? "23.976" :
78
+						vs.frame_rate_code == 2 ? "24.00" :
79
+						vs.frame_rate_code == 3 ? "25.00" :
80
+						vs.frame_rate_code == 4 ? "29.97" :
81
+						vs.frame_rate_code == 5 ? "30.00" :
82
+						vs.frame_rate_code == 6 ? "50.00" :
83
+						vs.frame_rate_code == 7 ? "59.94" :
84
+						vs.frame_rate_code == 8 ? "60.00" : "reserved"
85
+					);
86
+					ts_LOGf("%s  - mpeg1_only_flag              : %d\n", pad, vs.mpeg1_only_flag);
87
+					ts_LOGf("%s  - constraint_parameter_flag    : %d\n", pad, vs.constraint_parameter_flag);
88
+					ts_LOGf("%s  - still_picture_flag           : %d\n", pad, vs.still_picture_flag);
89
+				}
90
+				if (this_length >= 3 && vs.mpeg1_only_flag == 0) {
91
+					vs.profile_and_level_indication = data[1];
92
+					vs.chroma_format                = data[2] >> 6;				// xx111111
93
+					vs.frame_rate_extension_flag    = bit_on(data[2], bit_6);	// 11x11111
94
+					vs.reserved                     = data[2] &~ 0xE0;			// 111xxxxx
95
+					vs.profile                      = (vs.profile_and_level_indication &~ 0x8f) >> 4;	// x111xxxx
96
+					vs.level                        =  vs.profile_and_level_indication &~ 0xf0;			// xxxx1111
97
+					ts_LOGf("%s  - profile_and_level_indication : 0x%02x, Profile: %d (%s), Level: %d (%s)\n", pad,
98
+						vs.profile_and_level_indication,
99
+
100
+						vs.profile,
101
+						vs.profile == 1 ? "High"               :
102
+						vs.profile == 2 ? "Spatially Scalable" :
103
+						vs.profile == 3 ? "SNR Scalable"       :
104
+						vs.profile == 4 ? "Main"               :
105
+						vs.profile == 5 ? "Simple"             : "Reserved",
106
+
107
+						vs.level,
108
+						vs.level == 4  ? "High"      :
109
+						vs.level == 6  ? "High 1440" :
110
+						vs.level == 8  ? "Main"      :
111
+						vs.level == 10 ? "Low"       : "Reserved"
112
+					);
113
+					ts_LOGf("%s  - chroma_format                : %d (%s)\n", pad, vs.chroma_format,
114
+						vs.chroma_format == 0 ? "reserved" :
115
+						vs.chroma_format == 1 ? "4:2:0" :
116
+						vs.chroma_format == 2 ? "4:2:2" :
117
+						vs.chroma_format == 3 ? "4:4:4" : "unknown"
118
+					);
119
+					ts_LOGf("%s  - frame_rate_extension_flag    : %d\n", pad, vs.frame_rate_extension_flag);
120
+					ts_LOGf("%s  - reserved                     : 0x%x\n", pad, vs.reserved);
121
+				}
122
+				break;
123
+			}
124
+			case  3: { // Audio stream descriptor
125
+				char *dump = ts_hex_dump(data, this_length);
126
+				ts_LOGf("%sTag 0x%02x (%02d), sz: %d, Audio stream descriptor: %s\n", pad, tag, tag, this_length, dump);
127
+				free(dump);
128
+				struct {
129
+					uint8_t free_format_flag : 1,
130
+					        ID               : 1,
131
+					        layer            : 2,
132
+					        vbr_flag         : 1,
133
+					        reserved         : 3;
134
+				} as;
135
+				if (this_length >= 1) {
136
+					as.free_format_flag = bit_on(data[0], bit_8);
137
+					as.ID               = bit_on(data[0], bit_7);
138
+					as.layer            = (data[0] &~ 0xcf) >> 4;	// 11xx1111
139
+					as.vbr_flag         = bit_on(data[0], bit_4);
140
+					as.reserved         = data[0] &~ 0xf0;			// 1111xxxx
141
+					ts_LOGf("%s  - free_format_flag : %d\n", pad, as.free_format_flag);
142
+					ts_LOGf("%s  - ID               : %d (%s)\n", pad, as.ID, as.ID ? "MPEG Audio" : "Other");
143
+					ts_LOGf("%s  - layer            : %d (%s)\n", pad, as.layer,
144
+						as.layer == 0 ? "reserved" :
145
+						as.layer == 1 ? "Layer III" :
146
+						as.layer == 2 ? "Layer II" :
147
+						as.layer == 3 ? "Layer I" : "reserved"
148
+					);
149
+					ts_LOGf("%s  - vbr_audio_flag   : %d\n", pad, as.vbr_flag);
150
+					ts_LOGf("%s  - reserved         : 0x%x\n", pad, as.reserved);
151
+				}
152
+				break;
153
+			}
154
+			case  5: { // Registration descriptor
155
+				ts_LOGf("%sTag 0x%02x (%02d), sz: %d, Registration descriptor\n", pad, tag, tag, this_length);
156
+				uint32_t reg_ident  = data[0] << 24;
157
+				reg_ident          |= data[1] << 16;
158
+				reg_ident          |= data[2] << 8;
159
+				reg_ident          |= data[3];
160
+				// See http://smpte-ra.org/mpegreg/mpegreg.html
161
+				ts_LOGf("%s  Registration ident: 0x%04x (%c%c%c%c)\n", pad, reg_ident,
162
+					data[0], data[1], data[2], data[3]);
163
+				dvb_print_string(pad, "Registration data :", &data[4], this_length-4);
164
+				break;
165
+			}
166
+			case  6: { // I see this in data, so might as well "explain" it
167
+				ts_LOGf("%sTag 0x%02x (%02d), sz: %d, Data stream alignment descriptor: Alignment type: 0x%02x (%s)\n",
168
+					pad, tag, tag, this_length,
169
+					data[0],
170
+					data[0] == 0x00 ? "Reserved" :
171
+					data[0] == 0x01 ? "Slice, or video access unit" :
172
+					data[0] == 0x02 ? "Video access unit" :
173
+					data[0] == 0x03 ? "GOP, or SEQ" :
174
+					data[0] == 0x04 ? "SEQ" : "Reserved"
175
+				);
176
+				break;
177
+			}
178
+			case  9: { // I see this in data, so might as well "explain" it
179
+				ts_LOGf("%sTag 0x%02x (%02d), sz: %d, CA descriptor:\n", pad, tag, tag, this_length);
180
+				temp_u = (data[0] << 8) | data[1];
181
+				ts_LOGf("%sCA  id %04x (%02d)\n",pad,temp_u,temp_u);
182
+				temp_u = ((data[2] & 0x1F) << 8) | data[3];
183
+				ts_LOGf("%sCA PID %04x (%d)\n",pad,temp_u,temp_u);
184
+				break;
185
+			}
186
+			case 10: { // We'll assume the length is a multiple of 4
187
+				ts_LOGf("%sTag 0x%02x (%02d), sz: %d, Language descriptor:\n", pad, tag, tag, this_length);
188
+				for (i=0; i<this_length/4; i++) {
189
+					uint8_t audio_type = *(data+(i*4)+3);
190
+					ts_LOGf("%s  Lang: %c%c%c Type: (%d) %s\n", pad,
191
+							*(data+(i*4)+0), *(data+(i*4)+1), *(data+(i*4)+2),
192
+							audio_type,
193
+							(audio_type == 0 ? "" :
194
+							 audio_type == 1 ? "clean effects" :
195
+							 audio_type == 2 ? "visual impaired commentary" :
196
+							 audio_type == 3 ? "clean effects" : "reserved")
197
+					);
198
+				}
199
+				break;
200
+			}
201
+			case 14: { // Maximum bitrate descriptor
202
+				uint32_t max_bitrate = ((data[0] &~ 0xc0) << 16) | (data[1] << 8) | data[2]; // 11xxxxxx xxxxxxxx xxxxxxxx
203
+				ts_LOGf("%sTag 0x%02x (%02d), sz: %d, Maximum bitrate descriptor: 0x%04x (%u Bytes/sec)\n",
204
+					pad, tag, tag, this_length,
205
+					max_bitrate, max_bitrate * 50); // The value is in units of 50 bytes/second
206
+				break;
207
+			}
208
+			case 0x40: { // Network name descriptor
209
+				ts_LOGf("%sTag 0x%02x (%02d), sz: %d, Network name descriptor\n", pad, tag, tag, this_length);
210
+				dvb_print_string(pad, "Network name:", &data[0], this_length);
211
+				break;
212
+			}
213
+			case 0x41: { // service_list_descriptor
214
+				ts_LOGf("%sTag 0x%02x (%02d), sz: %d, Service_list_descriptor\n", pad, tag, tag, this_length);
215
+				for (i=0; i<this_length; i+=3) {
216
+					uint16_t service_id;
217
+					uint8_t service_type;
218
+					service_id   = data[i + 0] << 8;
219
+					service_id  |= data[i + 1];
220
+					service_type = data[i + 2];
221
+					ts_LOGf("%s  Service_Id: 0x%04x (%d) Type: 0x%02x (%d)\n", pad,
222
+						service_id, service_id,
223
+						service_type, service_type);
224
+				}
225
+				break;
226
+			}
227
+			case 0x44: { // cable_delivery_descriptor
228
+				ts_LOGf("%sTag 0x%02x (%02d), sz: %d, Cable_delivery_system descriptor\n", pad, tag, tag, this_length);
229
+				uint32_t freq, symbol_rate;
230
+				uint16_t reserved;
231
+				uint8_t FEC_outer, FEC_inner;
232
+				uint8_t modulation;
233
+				freq           = data[0] << 24;
234
+				freq          |= data[1] << 16;
235
+				freq          |= data[2] << 8;
236
+				freq          |= data[3];			// 4 bytes
237
+				reserved       = data[4] << 8;		// 11111111
238
+				reserved      |= data[5] &~ 0x0f;	// 1111xxxx
239
+				FEC_outer      = data[5] &~ 0xf0;	// xxxx1111
240
+				modulation     = data[6];			// 1 byte
241
+				symbol_rate    = data[7] << 24;
242
+				symbol_rate   |= data[8] << 16;
243
+				symbol_rate   |= data[9] << 8;		// 28 bits, the last 4 bits are FEC_inner
244
+				symbol_rate   |= data[10];			// 28 bits, the last 4 bits are FEC_inner
245
+				FEC_inner      = data[10] &~ 0xf0;
246
+				ts_LOGf("%s  Frequency  : 0x%08x\n", pad, freq);
247
+				ts_LOGf("%s  FEC_outer  : %s (0x%x) (reserved 0x%03x)\n"  , pad,
248
+					(FEC_outer == 0 ? "Not defined" :
249
+					 FEC_outer == 1 ? "no outer FEC coding" :
250
+					 FEC_outer == 2 ? "RS (204/188)" : "Reserved"),
251
+					FEC_outer, reserved >> 4);
252
+				ts_LOGf("%s  Modulation : %s (%d/0x%02x)\n", pad,
253
+					(modulation == 0 ? "Not defined" :
254
+					 modulation == 1 ? "16-QAM" : 
255
+					 modulation == 2 ? "32-QAM" : 
256
+					 modulation == 3 ? "64-QAM" : 
257
+					 modulation == 4 ? "128-QAM" : 
258
+					 modulation == 5 ? "256-QAM" : "Reserved"),
259
+					modulation, modulation);
260
+				ts_LOGf("%s  symbol_rate: 0x%07x\n", pad, symbol_rate);
261
+				ts_LOGf("%s  FEC_inner  : 0x%x\n"  , pad, FEC_inner);
262
+				break;
263
+			}
264
+			case 0x45: { // VBI_data_descriptor
265
+				ts_LOGf("%sTag 0x%02x (%02d), sz: %d, VBI_data descriptor (not decoded!!!)\n", pad, tag, tag, this_length);
266
+				break;
267
+			}
268
+			case 0x48: { // Service descriptor
269
+				ts_LOGf("%sTag 0x%02x (%02d), sz: %d, Service descriptor:\n", pad, tag, tag, this_length);
270
+				ts_LOGf("%s  Service type : %s\n", pad,
271
+					data[0] == 0x01 ? "digital tv service" :
272
+					data[0] == 0x02 ? "digital radio service" : "other");
273
+				uint8_t provider_name_length = data[1];
274
+				dvb_print_string(pad, "Provider name:", &data[2], provider_name_length);
275
+				uint8_t service_name_length = data[2 + provider_name_length];
276
+				dvb_print_string(pad, "Service name :", &data[3 + provider_name_length], service_name_length);
277
+				break;
278
+			}
279
+			case 0x4d: { // short_event_descriptor
280
+				ts_LOGf("%sTag 0x%02x (%02d), sz: %d, Short event descriptor:\n", pad, tag, tag, this_length);
281
+				ts_LOGf("%s  Lang : %c%c%c\n", pad, data[0], data[1], data[2]);
282
+				uint8_t event_name_length = data[3];
283
+				dvb_print_string(pad, "Event:", &data[4], event_name_length);
284
+				uint8_t text_length = data[4 + event_name_length];
285
+				dvb_print_string(pad, "Text :", &data[5 + event_name_length], text_length);
286
+				break;
287
+			}
288
+			case 0x4e: { // extended_event_descriptor
289
+				ts_LOGf("%sTag 0x%02x (%02d), sz: %d, Extended event descriptor:\n", pad, tag, tag, this_length);
290
+				uint8_t desc_number = data[0] >> 4;			// xxxx 1111
291
+				uint8_t last_desc_number = data[0] &~ 0xf0;	// 1111 xxxx
292
+				ts_LOGf("%s  Desc_number: %d Last Desc_number: %d\n", pad, desc_number, last_desc_number);
293
+				ts_LOGf("%s  Lang    : %c%c%c\n", pad, data[1], data[2], data[3]);
294
+				uint8_t items_length = data[4];
295
+				ts_LOGf("%s  ItemsLen: %d\n", pad, items_length);
296
+				i = 5;
297
+				while (i < items_length+5) {
298
+					uint8_t item_desc_len = data[i++];
299
+					if (item_desc_len)
300
+						dvb_print_string(pad, "  - Desc:", &data[i], item_desc_len);
301
+					i += item_desc_len;
302
+					uint8_t item_len = data[i++];
303
+					if (item_len)
304
+						dvb_print_string(pad, "  - Text:", &data[i], item_len);
305
+					i += item_len;
306
+				}
307
+				uint8_t text_length = data[5 + items_length];
308
+				dvb_print_string(pad, "Text    :", &data[6 + items_length], text_length);
309
+				break;
310
+			}
311
+			case 0x50: { // Component descriptor
312
+				ts_LOGf("%sTag 0x%02x (%02d), sz: %d, Component descriptor:\n", pad, tag, tag, this_length);
313
+				uint8_t reserved       = data[0] >> 4;		// 1111 xxxx
314
+				uint8_t stream_content = data[0] &~ 0xF0;	// xxxx 1111
315
+				uint8_t component_type = data[1];			// See Table 26 ETSI EN 300 468
316
+				uint8_t component_tag  = data[2];
317
+
318
+				ts_LOGf("%s  Stream_content: %d Component_type:%d Component_tag:%d res:0x%x\n", pad,
319
+					stream_content, component_type, component_tag, reserved);
320
+				ts_LOGf("%s  Lang : %c%c%c\n", pad, data[3], data[4], data[5]);
321
+				dvb_print_string(pad, "Text :", &data[6], this_length-6);
322
+				break;
323
+			}
324
+			case 0x52: { // Stream identifier descriptor
325
+				ts_LOGf("%sTag 0x%02x (%02d), sz: %d, Stream identifier descriptor: Component_tag: 0x%02x (%d)\n",
326
+					pad, tag, tag, this_length,
327
+					data[0], data[0]);
328
+				break;
329
+			}
330
+			case 0x54: { // Content descriptor
331
+				ts_LOGf("%sTag 0x%02x (%02d), sz: %d, Content descriptor:\n", pad, tag, tag, this_length);
332
+				for (i=0; i<this_length; i+=2) {
333
+					uint8_t c1 = data[i + 0] >> 4;
334
+					uint8_t c2 = data[i + 0] &~ 0xf0;
335
+					uint8_t u1 = data[i + 1] >> 4;
336
+					uint8_t u2 = data[i + 1] &~ 0xf0;
337
+					ts_LOGf("%s  Content1: %d Content2: %d User1: %d User2: %d\n", pad, c1, c2, u1 ,u2);
338
+				}
339
+				break;
340
+			}
341
+			case 0x55: { // Parental rating descriptor
342
+				ts_LOGf("%sTag 0x%02x (%02d), sz: %d, Parental rating descriptor:\n", pad, tag, tag, this_length);
343
+				for (i=0; i<this_length; i+=4) {
344
+					ts_LOGf("%s  Country: %c%c%c\n", pad, data[i+0], data[i+1], data[i+2]);
345
+					if (data[i+3] == 0)
346
+						ts_LOGf("%s  Rating : undefined\n", pad);
347
+					else if (data[i+3] >= 0x01 && data[i+3] <= 0x0f)
348
+						ts_LOGf("%s  Rating : min age %d years\n", pad, data[i+3] + 3);
349
+					else
350
+						ts_LOGf("%s  Rating : private - 0x%02x (%d)\n", pad, data[i+3], data[i+3]);
351
+				}
352
+				break;
353
+			}
354
+			case 0x56: { // teletext
355
+				ts_LOGf("%sTag 0x%02x (%02d), sz: %d, Teletext descriptor:\n", pad, tag, tag, this_length);
356
+				for (i=0; i<this_length; i+= 5) {
357
+					int teletext_type, teletext_magazine, teletext_page;
358
+					ts_LOGf("%s  Lang: %c%c%c\n", pad, data[i], data[i+1], data[i+2]);
359
+					teletext_type     = (data[i+3] & 0xF8) >> 3;
360
+					teletext_magazine = (data[i+3] & 0x07);
361
+					teletext_page     = data[i+4];
362
+					ts_LOGf("%s  Type: %d, Desc: %s\n", pad, teletext_type,
363
+							(teletext_type == 1 ? "Initial" :
364
+							 teletext_type == 2 ? "Subtitles" :
365
+							 teletext_type == 3 ? "Additional info" :
366
+							 teletext_type == 4 ? "Program schedule" :
367
+							 teletext_type == 5 ? "Hearing impaired subtitles" : "(reserved)")
368
+					);
369
+					ts_LOGf("%s  Magazine: %d, Page: %d\n", pad, teletext_magazine, teletext_page);
370
+				}
371
+				break;
372
+			}
373
+			case 0x58: { // local_timeoffset
374
+				ts_LOGf("%sTag 0x%02x (%02d), sz: %d, Local timeoffset descriptor\n", pad, tag, tag, this_length);
375
+				if (this_length == 13) {
376
+					uint16_t mjd, lto, lto_next;
377
+					uint32_t bcd;
378
+					time_t ts;
379
+					struct tm tm;
380
+					uint8_t region_id, reserved, polarity;
381
+					ts_LOGf("%s  Country code: %c%c%c\n", pad, data[0], data[1], data[2]);
382
+					region_id	 = data[ 3] >> 2;			// xxxxxx11
383
+					reserved	 =(data[ 3] &~ 0xfd) >> 1;	// 111111x1
384
+					polarity	 =(data[ 3] &~ 0xfe);		// 1111111x
385
+					lto			 = data[ 4] << 8;
386
+					lto			|= data[ 5];
387
+					mjd			 = data[ 6] << 8;
388
+					mjd			|= data[ 7];
389
+					bcd			 = data[ 8] << 16;
390
+					bcd			|= data[ 9] << 8;
391
+					bcd			|= data[10];
392
+					lto_next	 = data[11] << 8;
393
+					lto_next	|= data[12];
394
+					ts = ts_time_decode_mjd(mjd, bcd, &tm);
395
+					ts_LOGf("%s  Region_id   : %d\n", pad, region_id);
396
+					ts_LOGf("%s  Reserved    : %d\n", pad, reserved);
397
+					ts_LOGf("%s  LTO polarity: %d\n", pad, polarity);
398
+					ts_LOGf("%s  LTO         : %c%04x\n", pad, polarity ? '-' : '+', lto);
399
+					ts_LOGf("%s  Change time : (%04d-%02d-%02d %02d:%02d:%02d) /0x%04x%06x, %ld/\n", pad,
400
+						tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
401
+						tm.tm_hour, tm.tm_min, tm.tm_sec,
402
+						mjd, bcd, ts);
403
+					ts_LOGf("%s  LTO next    : %c%04x\n", pad, polarity ? '-' : '+', lto_next);
404
+				} else {
405
+					ts_LOGf("%s  !!! length != 13 (%d)\n", pad, this_length);
406
+				}
407
+				break;
408
+			}
409
+
410
+			case 0x59: {
411
+				ts_LOGf("%sTag 0x%02x (%02d), sz: %d, Subtitling descriptor:\n", pad, tag, tag, this_length);
412
+				for (i=0; i+8 <= this_length; i+=8) {
413
+					char lang[4];
414
+					unsigned int subtitling_type     =  data[i+3];
415
+					unsigned int composition_page_id = (data[i+4] << 8) | data[i+5];
416
+					unsigned int ancillary_page_id   = (data[i+6] << 8) | data[i+7];
417
+					lang[0] = data[i + 0];
418
+					lang[1] = data[i + 1];
419
+					lang[2] = data[i + 2];
420
+					lang[3] = 0;
421
+					ts_LOGf("%s  Lang: %s, Sub_type: %u, Composition_page_id: %u, Ancillary_page_id: %u\n",
422
+						pad, lang, subtitling_type, composition_page_id, ancillary_page_id);
423
+				}
424
+				break;
425
+			}
426
+			case 0x62: { // frequency_list_descriptor
427
+				ts_LOGf("%sTag 0x%02x (%02d), sz: %d, Frequency_list_descriptor\n", pad, tag, tag, this_length);
428
+				uint8_t reserved    = data[0] >> 2;		// 111111xx
429
+				uint8_t coding_type = data[0] &~ 0xfc;	// xxxxxx11
430
+				ts_LOGf("%s  Coding_type: %s (%d/0x%x) Reserved: 0x%x\n", pad,
431
+						(coding_type == 0 ? "Not defined" :
432
+						 coding_type == 1 ? "Satellite" :
433
+						 coding_type == 2 ? "Cable" :
434
+						 coding_type == 3 ? "Terrestrial" : "Reserved"),
435
+						 coding_type, coding_type, reserved);
436
+				for (i=1; i<this_length; i+=4) {
437
+					uint32_t centre_freq;
438
+					centre_freq  = data[i + 0] << 24;
439
+					centre_freq |= data[i + 1] << 16;
440
+					centre_freq |= data[i + 2] << 8;
441
+					centre_freq |= data[i + 3];
442
+					ts_LOGf("%s  Frequency: 0x%08x\n", pad, centre_freq);
443
+				}
444
+				break;
445
+			}
446
+
447
+			case 0x69: { // PDC descriptor
448
+				ts_LOGf("%sTag 0x%02x (%02d), sz: %d, PDC descriptor: Prg_id_label: 0x%02x%02x%02x\n",
449
+					pad, tag, tag, this_length,
450
+					data[0] &~ 0xf0, data[1], data[2]);
451
+				break;
452
+			}
453
+			case 0x6a: {
454
+				ts_LOGf("%sTag 0x%02x (%02d), sz: %d, AC-3 descriptor\n", pad, tag, tag, this_length);
455
+				break;
456
+			}
457
+/*
458
+			case 0x87: { // Private descriptor! LCN Logical channel descriptor
459
+				ts_LOGf("%sTag 0x%02x (%02d), sz: %d, Logical channel descriptor\n", pad, tag, tag, this_length);
460
+				for (i=0; i<= this_length; i+=4) {
461
+					uint16_t service_id = (data[0+i] << 8) | data[1+i];	// xxxxxxxx xxxxxxxx
462
+					uint8_t  visible    = (data[2+i] >> 7);				// x1111111
463
+//					uint8_t  reserved1  = (data[2+i] &~ 0x80) >> 2;		// 1xxxxx11
464
+					uint16_t lcn        = (data[2+i] &~ 0x3f);			// 111111xx
465
+					         lcn       |=  data[3+i];					// xxxxxxxx
466
+					ts_LOGf("%s  Service_ID: 0x%04x (%4d) LCN: %3d Visible: %d\n",
467
+						pad,
468
+						service_id, service_id,
469
+						lcn, visible);
470
+				}
471
+				break;
472
+			}
473
+*/
474
+			default: {
475
+				char *dump = ts_hex_dump(data, this_length);
476
+				ts_LOGf("%s*** Unknown Tag 0x%02x (%02d), sz: %d, data: %s\n", pad, tag, tag, this_length, dump);
477
+				free(dump);
478
+				break;
479
+			}
480
+		}
481
+		data_len -= this_length;
482
+		data += this_length;
483
+	}
484
+}

+ 297 - 0
tsfuncs_eit.c View File

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

+ 188 - 0
tsfuncs_eit_desc.c View File

@@ -0,0 +1,188 @@
1
+#include <stdio.h>
2
+#include <unistd.h>
3
+#include <netdb.h>
4
+#include <stdlib.h>
5
+#include <string.h>
6
+
7
+#include "tsfuncs.h"
8
+
9
+static void ts_eit_regenerate_packet_data(struct ts_eit *eit) {
10
+	uint8_t *ts_packets;
11
+	int num_packets;
12
+	ts_eit_generate(eit, &ts_packets, &num_packets);
13
+	memcpy(eit->section_header->packet_data, ts_packets, num_packets * TS_PACKET_SIZE);
14
+	eit->section_header->num_packets = num_packets;
15
+	free(ts_packets);
16
+}
17
+
18
+static void ts_eit_init_private_variables(struct ts_eit *eit) {
19
+	eit->section_header->data_size          = eit->section_header->section_length + 3;
20
+	eit->section_header->packet_section_len = eit->section_header->data_size - 8 - 4;	// -8 for the section header, -4 for the CRC at the end
21
+	ts_eit_regenerate_packet_data(eit);
22
+}
23
+
24
+struct ts_eit *ts_eit_alloc_init(uint16_t service_id, uint16_t transport_stream_id, uint16_t org_network_id, uint8_t table_id, uint8_t sec_number, uint8_t last_sec_number) {
25
+	struct ts_eit *eit = ts_eit_alloc();
26
+
27
+	eit->ts_header.pid            = 0x12;
28
+	eit->ts_header.pusi           = 1;
29
+	eit->ts_header.payload_field  = 1;
30
+	eit->ts_header.payload_offset = 4;
31
+
32
+	eit->section_header->table_id                 = table_id;
33
+	eit->section_header->version_number           = 1;
34
+	eit->section_header->current_next_indicator   = 1;
35
+	eit->section_header->section_syntax_indicator = 1;
36
+	eit->section_header->private_indicator        = 1;
37
+	eit->section_header->section_length           = 9 + 6;		// Empty section, +6 (16+16+8+8 bits) for EIT table data
38
+	eit->section_header->ts_id_number             = service_id;
39
+	eit->section_header->reserved1                = 3;
40
+	eit->section_header->reserved2                = 3;
41
+
42
+	eit->section_header->section_number           = sec_number;
43
+	eit->section_header->last_section_number      = last_sec_number;
44
+
45
+	eit->transport_stream_id         = transport_stream_id;		// 16 bits
46
+	eit->original_network_id         = org_network_id;			// 16 bits
47
+	eit->segment_last_section_number = 0;						// 8 bits
48
+	eit->last_table_id               = table_id;				// 8 bits
49
+
50
+	eit->initialized = 1;
51
+
52
+	ts_eit_init_private_variables(eit);
53
+	return eit;
54
+}
55
+
56
+struct ts_eit *ts_eit_alloc_init_pf(uint16_t service_id, uint16_t transport_stream_id, uint16_t org_network_id, uint8_t sec_number, uint8_t last_sec_number) {
57
+	return ts_eit_alloc_init(service_id, transport_stream_id, org_network_id, 0x4e, sec_number, last_sec_number);
58
+}
59
+
60
+struct ts_eit *ts_eit_alloc_init_schedule(uint16_t service_id, uint16_t transport_stream_id, uint16_t org_network_id, uint8_t sec_number, uint8_t last_sec_number) {
61
+	return ts_eit_alloc_init(service_id, transport_stream_id, org_network_id, 0x50, sec_number, last_sec_number);
62
+}
63
+
64
+
65
+static int ts_eit_add_stream(struct ts_eit *eit, uint16_t event_id, uint8_t running, time_t start_time, int duration_sec, uint8_t *desc, uint16_t desc_size) {
66
+	if (eit->streams_num == eit->streams_max - 1 || desc_size == 0) {
67
+		FREE(desc);
68
+		return 0;
69
+	}
70
+
71
+	uint16_t start_mjd;
72
+	uint32_t start_bcd;
73
+	uint32_t dur_bcd = ts_time_encode_bcd(duration_sec);
74
+	ts_time_encode_mjd(&start_mjd, &start_bcd, &start_time, NULL);
75
+
76
+	int stream_len = 12 + desc_size;
77
+	if (stream_len + eit->section_header->section_length > 4093) {
78
+		ts_LOGf("EIT no space left, max 4093, current %d will become %d!\n",
79
+			eit->section_header->section_length,
80
+			stream_len + eit->section_header->section_length);
81
+		free(desc);
82
+		return 0;
83
+	}
84
+
85
+	eit->section_header->section_length += stream_len;
86
+
87
+	struct ts_eit_stream *sinfo = calloc(1, sizeof(struct ts_eit_stream));
88
+	sinfo->event_id            = event_id;		// 2 bytes (16 bits)
89
+	sinfo->start_time_mjd      = start_mjd;		// 5 bytes (40 bits)
90
+	sinfo->start_time_bcd      = start_bcd;		//
91
+	sinfo->duration_bcd        = dur_bcd;		// 3 bytes (24 bits)
92
+
93
+	sinfo->running_status      = running;		// 2 bytes (3 bits), 1 == not running, 4 == running
94
+	sinfo->free_CA_mode        = 0;				//         (1 bit) , 0 == not scrambled
95
+	sinfo->descriptor_size     = desc_size;		//         (12 bits)
96
+
97
+	sinfo->descriptor_data     = desc;			// desc_size bytes
98
+
99
+	eit->streams[eit->streams_num] = sinfo;
100
+	eit->streams_num++;
101
+
102
+	ts_eit_init_private_variables(eit);
103
+
104
+	return 1;
105
+}
106
+
107
+int ts_eit_add_short_event_descriptor(struct ts_eit *eit, uint16_t event_id, uint8_t running, time_t start_time, int duration_sec, char *event_name, char *event_short_descr) {
108
+	char *txt;
109
+	uint8_t event_len = event_name ? strlen(event_name) : 0;
110
+	uint8_t descr_len = event_short_descr ? strlen(event_short_descr) : 0;
111
+
112
+	int desc_size = 2 + 3; // 2 bytes tag header, 3 bytes ISO lang code
113
+	desc_size += 1 + event_len;
114
+	desc_size += 1 + descr_len;
115
+	if (desc_size > 255) {
116
+		ts_LOGf("EIT short event descriptor size > 255 is not supported (%d)!\n", desc_size);
117
+		return 0;
118
+	}
119
+	if (event_len == 0) {
120
+		ts_LOGf("EIT event_len == 0!\n");
121
+		return 0;
122
+	}
123
+	uint8_t *desc = calloc(1, desc_size);
124
+
125
+	int dpos = 0;
126
+	desc[dpos +  0] = 0x4d;							// Short_event_descriptor
127
+	desc[dpos +  1] = desc_size - 2;					// -2 Because of two byte header
128
+	desc[dpos +  2] = 'b';
129
+	desc[dpos +  3] = 'u';
130
+	desc[dpos +  4] = 'l';
131
+	desc[dpos +  5] = event_len;
132
+	dpos += 6;
133
+	txt = event_name;
134
+	while (txt[0]) {
135
+		desc[dpos++] = txt[0];
136
+		txt++;
137
+	}
138
+	desc[dpos++   ] = descr_len;
139
+	if (descr_len) {
140
+		txt = event_short_descr;
141
+		while (txt[0]) {
142
+			desc[dpos++] = txt[0];
143
+			txt++;
144
+		}
145
+	}
146
+
147
+	return ts_eit_add_stream(eit, event_id, running ? 4 : 1, start_time, duration_sec, desc, dpos);
148
+}
149
+
150
+
151
+int ts_eit_add_extended_event_descriptor(struct ts_eit *eit, uint16_t event_id, uint8_t running, time_t start_time, int duration_sec, char *text) {
152
+	if (!text)
153
+		return 0;
154
+	char *txt;
155
+	int desc_size = 2 + 3 + 1 + 1;	// 2 bytes tag header
156
+									// 3 bytes ISO lang code
157
+									// 1 byte, desc_number, last_desc_number (4 bits + 4 bits)
158
+									// 1 byte length of items (0 because items are unsupported)
159
+	int text_len = strlen(text);
160
+	desc_size += 1 + text_len;
161
+	if (desc_size > 257) {
162
+		ts_LOGf("EIT extended event descriptor size > 255 is not supported (%d)!\n", desc_size);
163
+		return 0;
164
+	}
165
+	if (text_len == 0) {
166
+		ts_LOGf("EIT text_len == 0!\n");
167
+		return 0;
168
+	}
169
+	uint8_t *desc = calloc(1, desc_size);
170
+
171
+	int dpos = 0;
172
+	desc[dpos +  0] = 0x4e;			 // Extended_event_descriptor
173
+	desc[dpos +  1] = desc_size - 2; // -2 Because of two byte header
174
+	desc[dpos +  2] = (0 << 4) | (0 &~ 0xf0);	 // descriptor_number, last_descriptor_number;
175
+	desc[dpos +  3] = 'b';
176
+	desc[dpos +  4] = 'u';
177
+	desc[dpos +  5] = 'l';
178
+	desc[dpos +  6] = 0;						 // Length of items (items are not supported)
179
+	desc[dpos +  7] = text_len;
180
+	dpos += 8;
181
+	txt = text;
182
+	while (txt[0]) {
183
+		desc[dpos++] = txt[0];
184
+		txt++;
185
+	}
186
+
187
+	return ts_eit_add_stream(eit, event_id, running ? 4 : 1, start_time, duration_sec, desc, dpos);
188
+}

+ 51 - 0
tsfuncs_eit_test.c View File

@@ -0,0 +1,51 @@
1
+#include "tsfuncs.h"
2
+
3
+void test1(struct ts_eit *eit) { // Exactly one TS packet (188 bytes)
4
+	ts_eit_add_short_event_descriptor(eit, 4, time(NULL), 3600,
5
+		"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
6
+		"yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy****");
7
+}
8
+
9
+void test2(struct ts_eit *eit) { // One TS packet + 2 bytes (2 bytes of the CRC are in the next packet
10
+	ts_eit_add_short_event_descriptor(eit, 4, time(NULL), 3600,
11
+		"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
12
+		"yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy**");
13
+}
14
+
15
+void test3(struct ts_eit *eit) { // Test 4096 PSI packet
16
+	int i;
17
+	for (i=0;i<15;i++) {
18
+		// Maximum descriptor size, 255 bytes
19
+		if (ts_eit_add_short_event_descriptor(eit, 4, time(NULL), 3600, "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx") != 1) {
20
+			break;
21
+		}
22
+	}
23
+	ts_eit_add_short_event_descriptor(eit, 4, time(NULL), 3600, "00000000000000000000000", "1111111111111111111111111111111");
24
+}
25
+
26
+void test4(struct ts_eit *eit) { // Test almost full PSI packet on the TS packet boundary
27
+	int i;
28
+	for (i=0;i<15;i++) {
29
+		// Maximum descriptor size, 255 bytes
30
+		if (ts_eit_add_short_event_descriptor(eit, 4, time(NULL), 3600, "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx") != 1) {
31
+			break;
32
+		}
33
+	}
34
+	ts_eit_add_short_event_descriptor(eit, 4, time(NULL), 3600, "aaaaaaaaBBBB", NULL);
35
+}
36
+
37
+int main(int argc, char **argv) {
38
+	int i;
39
+	struct ts_eit *eit = ts_eit_alloc_init(1, 2, 3);
40
+
41
+//	test1(eit);
42
+//	test2(eit);
43
+//	test3(eit);
44
+//	test4(eit);
45
+
46
+	ts_eit_dump(eit);
47
+//	write(1, eit->section_header->packet_data, eit->section_header->num_packets * TS_PACKET_SIZE);
48
+
49
+	ts_eit_free(eit);
50
+	return 0;
51
+}

+ 184 - 0
tsfuncs_misc.c View File

@@ -0,0 +1,184 @@
1
+#include <stdio.h>
2
+#include <unistd.h>
3
+#include <netdb.h>
4
+#include <stdlib.h>
5
+#include <string.h>
6
+#include <ctype.h>
7
+
8
+#include "tsfuncs.h"
9
+
10
+int dec2bcd(int dec) {
11
+	return ((dec/10) << 4) + dec % 10;
12
+}
13
+
14
+int bcd2dec(int bcd) {
15
+	return ((bcd>>4) * 10) + bcd % 16;
16
+}
17
+
18
+char *ts_hex_dump(uint8_t *d, int size) {
19
+	int i;
20
+	char *buf = calloc(1, size * 6);
21
+	if (!buf)
22
+		return NULL;
23
+	for (i=0;i<size;i++) {
24
+		if (size > 188 && (i % 16 == 15))
25
+			sprintf(buf+(i*3), "%02x\n", d[i]);
26
+		else
27
+			sprintf(buf+(i*3), "%02x ", d[i]);
28
+	}
29
+	return buf;
30
+}
31
+
32
+void ts_print_bytes(char *prefix, uint8_t *d, int size) {
33
+	char *buf = ts_hex_dump(d, size);
34
+	ts_LOGf("%s -> %s\n", prefix, buf);
35
+	free(buf);
36
+}
37
+
38
+void ts_compare_data(char *prefix, uint8_t *a, uint8_t *b, int size) {
39
+	if (!a) {
40
+		ts_LOGf("%s: !a\n", prefix);
41
+		return;
42
+	}
43
+	if (!b) {
44
+		ts_LOGf("%s: !b\n", prefix);
45
+		return;
46
+	}
47
+	if (memcmp(a, b, size) == 0) {
48
+		ts_LOGf("   **** %s generator is correct ****\n", prefix);
49
+	} else {
50
+		int i;
51
+		for (i=0;i<size;i++) {
52
+			ts_LOGf("%03d - %02x %02x | %s\n", i, a[i], b[i], a[i] == b[i] ? "ok" : "err");
53
+		}
54
+	}
55
+}
56
+
57
+char *init_dvb_string(uint8_t encoding, char *text) {
58
+	if (!text)
59
+		return NULL;
60
+	int len = strlen(text);
61
+	if (!len)
62
+		return NULL;
63
+	char *dvbtext = calloc(1, len + 2);
64
+	memcpy(dvbtext + 1, text, len);
65
+	dvbtext[0] = encoding; // See EN 300 469 table A.3
66
+	return dvbtext;
67
+}
68
+
69
+char *init_dvb_string_utf8(char *text) {
70
+	return init_dvb_string(0x10, text);
71
+}
72
+
73
+char *init_dvb_string_iso_8859_5(char *text) {
74
+	return init_dvb_string(0x01, text);
75
+}
76
+
77
+int ts_is_psi_pid(uint16_t pid, struct ts_pat *pat) {
78
+	// Skip PAT && reserved, SDT, EIT, RST, TDT/TOT. They are PSI packets
79
+	if (pid < 0x10 || pid == 0x11 || pid == 0x12 || pid == 0x13 || pid == 0x14)
80
+		return 1;
81
+
82
+	int i;
83
+	for (i=0;i<pat->programs_num;i++) {
84
+		struct ts_pat_program *prg = pat->programs[i];
85
+		if (prg->pid == pid) // PMT's are PSI
86
+			return 1;
87
+	}
88
+	return 0;
89
+}
90
+
91
+int ts_is_stream_type_video(uint8_t stream_type) {
92
+	return	stream_type == STREAM_TYPE_MPEG1_VIDEO ||
93
+			stream_type == STREAM_TYPE_MPEG2_VIDEO ||
94
+			stream_type == STREAM_TYPE_AVC_VIDEO   ||
95
+			stream_type == STREAM_TYPE_AVS_VIDEO   ||
96
+			stream_type == STREAM_TYPE_MPEG4_PART2_VIDEO;
97
+}
98
+
99
+// This is not enough! Must look at stream descriptors to be sure!!!
100
+int ts_is_stream_type_ac3(uint8_t stream_type) {
101
+	return	stream_type == STREAM_TYPE_DOLBY_DVB_AUDIO ||
102
+			stream_type == STREAM_TYPE_DOLBY_ATSC_AUDIO;
103
+}
104
+
105
+int ts_is_stream_type_audio(uint8_t stream_type) {
106
+	return	stream_type == STREAM_TYPE_MPEG1_AUDIO ||
107
+			stream_type == STREAM_TYPE_MPEG2_AUDIO ||
108
+			stream_type == STREAM_TYPE_ADTS_AUDIO  ||
109
+			ts_is_stream_type_ac3(stream_type);
110
+}
111
+
112
+// ISO/IEC 13818-1 : 2000 (E) | Table 2-29 - Stream type assignments, Page 66 (48)
113
+char *h222_stream_type_desc(uint8_t stream_type) {
114
+	if (stream_type == 0 || (stream_type > 0x1c && stream_type < 0x7e))
115
+		return "Reserved";
116
+	switch (stream_type) {
117
+		case 0x01: return "11172-2 video (MPEG-1)";
118
+		case 0x02: return "H.262/13818-2 video (MPEG-2) or 11172-2 constrained video";
119
+		case 0x03: return "11172-3 audio (MPEG-1)";
120
+		case 0x04: return "13818-3 audio (MPEG-2)";
121
+		case 0x05: return "H.222.0/13818-1  private sections";
122
+		case 0x06: return "H.222.0/13818-1 PES private data";
123
+		case 0x07: return "13522 MHEG";
124
+		case 0x08: return "H.222.0/13818-1 Annex A - DSM CC";
125
+		case 0x09: return "H.222.1";
126
+		case 0x0A: return "13818-6 type A";
127
+		case 0x0B: return "13818-6 type B";
128
+		case 0x0C: return "13818-6 type C";
129
+		case 0x0D: return "13818-6 type D";
130
+		case 0x0E: return "H.222.0/13818-1 auxiliary";
131
+		case 0x0F: return "13818-7 Audio with ADTS transport syntax";
132
+		case 0x10: return "14496-2 Visual (MPEG-4 part 2 video)";
133
+		case 0x11: return "14496-3 Audio with LATM transport syntax (14496-3/AMD 1)";
134
+		case 0x12: return "14496-1 SL-packetized or FlexMux stream in PES packets";
135
+		case 0x13: return "14496-1 SL-packetized or FlexMux stream in 14496 sections";
136
+		case 0x14: return "ISO/IEC 13818-6 Synchronized Download Protocol";
137
+		case 0x15: return "Metadata in PES packets";
138
+		case 0x16: return "Metadata in metadata_sections";
139
+		case 0x17: return "Metadata in 13818-6 Data Carousel";
140
+		case 0x18: return "Metadata in 13818-6 Object Carousel";
141
+		case 0x19: return "Metadata in 13818-6 Synchronized Download Protocol";
142
+		case 0x1A: return "13818-11 MPEG-2 IPMP stream";
143
+		case 0x1B: return "H.264/14496-10 video (MPEG-4/AVC)";
144
+		case 0x42: return "AVS Video";
145
+		case 0x7F: return "IPMP stream";
146
+		default  : return "Unknown";
147
+	}
148
+}
149
+
150
+// System start codes, ISO 13818-1, Table 2-18
151
+// The function allocates memory which should be freed by the caller
152
+char *h222_stream_id_desc(uint8_t stream_id) {
153
+	uint8_t stream_number;
154
+	char *text = NULL;
155
+	switch (stream_id) {
156
+		case 0xbc: return strdup("Program stream map"); break;
157
+		case 0xbd: return strdup("Private stream 1"); break;
158
+		case 0xbe: return strdup("Padding stream"); break;
159
+		case 0xbf: return strdup("Private stream 2"); break;
160
+		case 0xf0: return strdup("ECM stream"); break;
161
+		case 0xf1: return strdup("EMM stream"); break;
162
+		case 0xf2: return strdup("DSMCC stream"); break;
163
+		case 0xf3: return strdup("13522 stream"); break;
164
+		case 0xf4: return strdup("H.222 A stream"); break;
165
+		case 0xf5: return strdup("H.222 B stream"); break;
166
+		case 0xf6: return strdup("H.222 C stream"); break;
167
+		case 0xf7: return strdup("H.222 D stream"); break;
168
+		case 0xf8: return strdup("H.222 E stream"); break;
169
+		case 0xf9: return strdup("Ancillary stream"); break;
170
+		case 0xff: return strdup("Program stream directory"); break;
171
+	}
172
+	if (stream_id >= 0xc0 && stream_id <= 0xdf) {
173
+		stream_number = stream_id & 0x1f;
174
+		asprintf(&text, "Audio stream %d", stream_number);
175
+	} else if (stream_id >= 0xe0 && stream_id <= 0xef) {
176
+		stream_number = stream_id & 0x0f;
177
+		asprintf(&text, "Video stream %d", stream_number);
178
+	} else if (stream_id >= 0xfc && stream_id <= 0xfe) {
179
+		asprintf(&text, "Reserved data stream");
180
+	} else {
181
+		asprintf(&text, "Unrecognised stream id 0x%02x", stream_id);
182
+	}
183
+	return text;
184
+}

+ 267 - 0
tsfuncs_nit.c View File

@@ -0,0 +1,267 @@
1
+#include <stdio.h>
2
+#include <unistd.h>
3
+#include <netdb.h>
4
+#include <stdlib.h>
5
+#include <string.h>
6
+
7
+#include "tsfuncs.h"
8
+
9
+struct ts_nit *ts_nit_alloc() {
10
+	struct ts_nit *nit = calloc(1, sizeof(struct ts_nit));
11
+	nit->section_header = ts_section_data_alloc();
12
+	nit->streams_max = 128;
13
+	nit->streams = calloc(nit->streams_max, sizeof(void *));
14
+	return nit;
15
+}
16
+
17
+void ts_nit_free(struct ts_nit **pnit) {
18
+	struct ts_nit *nit = *pnit;
19
+	int i;
20
+	if (nit) {
21
+		ts_section_data_free(&nit->section_header);
22
+		FREE(nit->network_info);
23
+		for (i=0;i<nit->streams_num;i++) {
24
+			if (nit->streams[i]) {
25
+				FREE(nit->streams[i]->descriptor_data);
26
+				FREE(nit->streams[i]);
27
+			}
28
+		}
29
+		FREE(nit->streams);
30
+		FREE(*pnit);
31
+	}
32
+}
33
+
34
+static struct ts_nit *ts_nit_reset(struct ts_nit *nit) {
35
+	struct ts_nit *newnit = ts_nit_alloc();
36
+	ts_nit_free(&nit);
37
+	return newnit;
38
+}
39
+
40
+struct ts_nit *ts_nit_push_packet(struct ts_nit *nit, uint8_t *ts_packet) {
41
+	struct ts_header ts_header;
42
+	memset(&ts_header, 0, sizeof(struct ts_header));
43
+
44
+	if (ts_packet_header_parse(ts_packet, &ts_header)) {
45
+		// NIT should be with PID 0x10
46
+		if (ts_header.pid != 0x10)
47
+			goto OUT;
48
+		if (!nit->ts_header.pusi)
49
+			nit->ts_header = ts_header;
50
+	}
51
+
52
+	if (ts_header.pusi) {
53
+		struct ts_section_header section_header;
54
+		memset(&section_header, 0, sizeof(struct ts_section_header));
55
+
56
+		uint8_t *section_data = ts_section_header_parse(ts_packet, &nit->ts_header, &section_header);
57
+		if (!section_data || !section_header.section_syntax_indicator)
58
+			goto OUT;
59
+		// table_id should be 0x40 (network_information_section - actual_network)
60
+		if (section_header.table_id != 0x40) {
61
+			memset(&nit->ts_header, 0, sizeof(struct ts_header));
62
+			goto OUT;
63
+		}
64
+
65
+		// Set correct section_header
66
+		ts_section_header_parse(ts_packet, &nit->ts_header, nit->section_header);
67
+	}
68
+
69
+	if (!nit->initialized) {
70
+		if (nit->section_header->section_syntax_indicator) {
71
+			ts_section_add_packet(nit->section_header, &ts_header, ts_packet);
72
+			if (nit->section_header->initialized) {
73
+				if (!ts_nit_parse(nit))
74
+					goto ERROR;
75
+			}
76
+		}
77
+	}
78
+
79
+OUT:
80
+	return nit;
81
+
82
+ERROR:
83
+	return ts_nit_reset(nit);
84
+}
85
+
86
+
87
+int ts_nit_parse(struct ts_nit *nit) {
88
+	uint8_t *section_data = nit->section_header->section_data + 8; // + 8 to compensate for section table header
89
+	int section_len = nit->section_header->packet_section_len;
90
+
91
+	/* Table data (2 bytes) */
92
+	nit->reserved1         =  (section_data[0] &~ 0x0F) >> 4;						// xxxx1111
93
+	nit->network_info_size = ((section_data[0] &~ 0xF0) << 8) | section_data[1];	// 1111xxxx xxxxxxxx
94
+
95
+	/* Handle streams */
96
+	uint8_t *stream_data = section_data + 2 + nit->network_info_size;	// +2 is to compensate for reserved1 and network_info_size
97
+	int stream_len       = section_len - nit->network_info_size - 4;	// -4 for the CRC at the end
98
+
99
+	nit->network_info = NULL;
100
+	if (nit->network_info_size) {
101
+		nit->network_info = malloc(nit->network_info_size);
102
+		if (nit->network_info) {
103
+			memcpy(nit->network_info, stream_data - nit->network_info_size, nit->network_info_size);
104
+		}
105
+	}
106
+
107
+	// Before the table there are two more fields
108
+	nit->reserved2    =  (stream_data[0] &~ 0x0F) >> 4;						// xxxx1111
109
+	nit->ts_loop_size = ((stream_data[0] &~ 0xF0) << 8) | stream_data[1];	// 1111xxxx xxxxxxxx
110
+
111
+	stream_data += 2;
112
+	stream_len   = nit->ts_loop_size;
113
+
114
+	while (stream_len > 0) {
115
+		if (nit->streams_num == nit->streams_max) {
116
+			ts_LOGf("!!! Too many streams in NIT, max %d\n", nit->streams_max);
117
+			break;
118
+		}
119
+
120
+		struct ts_nit_stream *sinfo = calloc(1, sizeof(struct ts_nit_stream));
121
+
122
+		sinfo->transport_stream_id = (stream_data[0] << 8) | stream_data[1];
123
+		sinfo->original_network_id = (stream_data[2] << 8) | stream_data[3];
124
+
125
+		sinfo->reserved1           =  (stream_data[4] &~ 0x0F) >> 4;					// xxxx1111
126
+		sinfo->descriptor_size     = ((stream_data[4] &~ 0xF0) << 8) | stream_data[5];	// 1111xxxx xxxxxxxx
127
+
128
+		sinfo->descriptor_data      = NULL;
129
+		if (sinfo->descriptor_size > 0) {
130
+			sinfo->descriptor_data = malloc(sinfo->descriptor_size);
131
+			memcpy(sinfo->descriptor_data, &stream_data[6], sinfo->descriptor_size);
132
+		}
133
+		nit->streams[nit->streams_num] = sinfo;
134
+		nit->streams_num++;
135
+
136
+		stream_data += 6 + sinfo->descriptor_size;
137
+		stream_len  -= 6 + sinfo->descriptor_size;
138
+	}
139
+
140
+	nit->CRC = (nit->CRC << 8) | stream_data[3];
141
+	nit->CRC = (nit->CRC << 8) | stream_data[2];
142
+	nit->CRC = (nit->CRC << 8) | stream_data[1];
143
+	nit->CRC = (nit->CRC << 8) | stream_data[0];
144
+
145
+	u_int32_t check_crc = ts_crc32(nit->section_header->section_data, nit->section_header->data_size);
146
+	if (check_crc != 0) {
147
+		ts_LOGf("!!! Wrong NIT CRC! It should be 0 but it is %08x (CRC in data is 0x%08x)\n", check_crc, nit->CRC);
148
+		return 0;
149
+	}
150
+
151
+	nit->initialized = 1;
152
+	return 1;
153
+}
154
+
155
+void ts_nit_generate(struct ts_nit *nit, uint8_t **ts_packets, int *num_packets) {
156
+	uint8_t *secdata = ts_section_data_alloc_section();
157
+	ts_section_header_generate(secdata, nit->section_header, 0);
158
+	int curpos = 8; // Compensate for the section header, frist data byte is at offset 8
159
+
160
+	secdata[curpos + 0]  = nit->reserved1 << 4;			// xxxx1111
161
+	secdata[curpos + 0] |= nit->network_info_size >> 8;	// 1111xxxx xxxxxxxx
162
+	secdata[curpos + 1]  = nit->network_info_size &~ 0xff00;
163
+	curpos += 2; // For the fields above
164
+
165
+	if (nit->network_info_size) {
166
+		memcpy(secdata + curpos, nit->network_info, nit->network_info_size);
167
+		curpos += nit->network_info_size;
168
+	}
169
+
170
+	// Before the table there are two more fields
171
+	secdata[curpos + 0]  = nit->reserved2 << 4;			// xxxx1111
172
+	secdata[curpos + 0] |= nit->ts_loop_size >> 8;		// 1111xxxx xxxxxxxx
173
+	secdata[curpos + 1]  = nit->ts_loop_size &~ 0xff00;
174
+	curpos += 2; // For the fields above
175
+
176
+	int i;
177
+	for(i=0;i<nit->streams_num;i++) {
178
+		struct ts_nit_stream *stream = nit->streams[i];
179
+
180
+		secdata[curpos + 0]  = stream->transport_stream_id >> 8;			// xxxxxxxx xxxxxxxx
181
+		secdata[curpos + 1]  = stream->transport_stream_id &~ 0xff00;
182
+
183
+		secdata[curpos + 2]  = stream->original_network_id >> 8;			// xxxxxxxx xxxxxxxx
184
+		secdata[curpos + 3]  = stream->original_network_id &~ 0xff00;
185
+
186
+		secdata[curpos + 4]  = stream->reserved1 << 4;						// xxxx1111
187
+		secdata[curpos + 4] |= stream->descriptor_size >> 8;				// 1111xxxx xxxxxxxx
188
+
189
+		secdata[curpos + 5]  = stream->descriptor_size &~ 0xff00;
190
+
191
+		curpos += 6; // Compensate for the above
192
+
193
+		if (stream->descriptor_size > 0) {
194
+			memcpy(secdata + curpos, stream->descriptor_data, stream->descriptor_size);
195
+			curpos += stream->descriptor_size;
196
+		}
197
+	}
198
+	nit->CRC = ts_section_data_calculate_crc(secdata, curpos);
199
+	curpos += 4; // CRC
200
+
201
+	ts_section_data_gen_ts_packets(&nit->ts_header, secdata, curpos, nit->section_header->pointer_field, ts_packets, num_packets);
202
+
203
+	FREE(secdata);
204
+}
205
+
206
+void ts_nit_check_generator(struct ts_nit *nit) {
207
+	struct ts_nit *nit1 = ts_nit_alloc();
208
+	int i;
209
+	for (i=0;i<nit->section_header->num_packets;i++) {
210
+		nit1 = ts_nit_push_packet(nit1, nit->section_header->packet_data + (i * TS_PACKET_SIZE));
211
+	}
212
+	ts_compare_data("NIT (tspacket->struct)",
213
+		nit1->section_header->packet_data,
214
+		nit->section_header->packet_data,
215
+		nit->section_header->num_packets * TS_PACKET_SIZE);
216
+	ts_nit_free(&nit1);
217
+
218
+	uint8_t *ts_packets;
219
+	int num_packets;
220
+	ts_nit_generate(nit, &ts_packets, &num_packets);
221
+	if (num_packets != nit->section_header->num_packets) {
222
+		ts_LOGf("ERROR: num_packets:%d != sec->num_packets:%d\n", num_packets, nit->section_header->num_packets);
223
+	}
224
+	ts_compare_data("NIT (struct->tspacket)", nit->section_header->packet_data, ts_packets, num_packets * TS_PACKET_SIZE);
225
+	free(ts_packets);
226
+}
227
+
228
+void ts_nit_dump(struct ts_nit *nit) {
229
+	int i;
230
+	ts_LOGf("NIT table\n");
231
+	ts_LOGf("  * TS Packets\n");
232
+	for(i=0;i<nit->section_header->num_packets;i++) {
233
+		struct ts_header tshdr;
234
+		ts_packet_header_parse(nit->section_header->packet_data + (i * TS_PACKET_SIZE), &tshdr);
235
+		ts_packet_header_dump(&tshdr);
236
+	}
237
<