Browse Source

Initial import

Georgi Chorbadzhiyski 13 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

1
+*.o
2
+*.a

+ 35
- 0
Makefile View File

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

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

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

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

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

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

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

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

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

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

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

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

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
+	ts_section_header_dump(nit->section_header);
238
+	ts_LOGf("  * NIT data\n");
239
+	ts_LOGf("    * PID         : 0x%04x (%d)\n", nit->ts_header.pid, nit->ts_header.pid);
240
+	ts_LOGf("    * reserved1   : 0x%02x\n", nit->reserved1);
241
+	ts_LOGf("    * network_len : 0x%02x (%d)\n", nit->network_info_size, nit->network_info_size);
242
+	ts_LOGf("    * reserved2   : 0x%02x\n", nit->reserved1);
243
+	ts_LOGf("    * ts_loop_len : %d\n", nit->ts_loop_size);
244
+	ts_LOGf("    * num_streams : %d\n", nit->streams_num);
245
+
246
+	if (nit->network_info_size > 0) {
247
+		ts_LOGf("  * Network info:\n");
248
+		ts_LOGf("      * network info size: %d\n", nit->network_info_size);
249
+		ts_descriptor_dump(nit->network_info, nit->network_info_size);
250
+	}
251
+
252
+	for(i=0;i<nit->streams_num;i++) {
253
+		struct ts_nit_stream *stream = nit->streams[i];
254
+		ts_LOGf("    - [%02d/%02d] | TS_id: 0x%04x (%d) ORG_net_id: 0x%04x (%d) Reserved: 0x%0x Desc_size: %d\n",
255
+			i+1, nit->streams_num,
256
+			stream->transport_stream_id, stream->transport_stream_id,
257
+			stream->original_network_id, stream->original_network_id,
258
+			stream->reserved1,
259
+			stream->descriptor_size);
260
+		if (stream->descriptor_data) {
261
+			ts_descriptor_dump(stream->descriptor_data, stream->descriptor_size);
262
+		}
263
+	}
264
+	ts_LOGf("  * CRC 0x%04x\n", nit->CRC);
265
+
266
+	ts_nit_check_generator(nit);
267
+}

+ 179
- 0
tsfuncs_nit_desc.c View File

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_nit_regenerate_packet_data(struct ts_nit *nit) {
10
+	uint8_t *ts_packets;
11
+	int num_packets;
12
+	ts_nit_generate(nit, &ts_packets, &num_packets);
13
+	memcpy(nit->section_header->packet_data, ts_packets, num_packets * TS_PACKET_SIZE);
14
+	nit->section_header->num_packets = num_packets;
15
+	free(ts_packets);
16
+}
17
+
18
+static void ts_nit_init_private_variables(struct ts_nit *nit) {
19
+	nit->section_header->data_size          = nit->section_header->section_length + 3;
20
+	nit->section_header->packet_section_len = nit->section_header->data_size - 8 - 4;	// -8 for the section header, -4 for the CRC at the end
21
+	ts_nit_regenerate_packet_data(nit);
22
+}
23
+
24
+struct ts_nit *ts_nit_alloc_init(uint16_t network_id) {
25
+	struct ts_nit *nit = ts_nit_alloc();
26
+
27
+	nit->ts_header.pid            = 0x10;
28
+	nit->ts_header.pusi           = 1;
29
+	nit->ts_header.payload_field  = 1;
30
+	nit->ts_header.payload_offset = 4;
31
+
32
+	nit->section_header->table_id                 = 0x40;
33
+	nit->section_header->version_number           = 1;
34
+	nit->section_header->current_next_indicator   = 1;
35
+	nit->section_header->section_syntax_indicator = 1;
36
+	nit->section_header->private_indicator        = 1;
37
+	nit->section_header->section_length           = 9 + 4; // Empty section, +4 (16+16) for NIT table data
38
+	nit->section_header->ts_id_number             = network_id;
39
+	nit->section_header->reserved1                = 3;
40
+	nit->section_header->reserved2                = 3;
41
+
42
+	nit->reserved1           = 0xf;
43
+	nit->network_info_size   = 0;		// 16 bits
44
+	nit->reserved2           = 0xf;
45
+	nit->ts_loop_size        = 0;		// 16 bits
46
+
47
+	nit->initialized = 1;
48
+
49
+	ts_nit_init_private_variables(nit);
50
+
51
+	return nit;
52
+}
53
+
54
+int ts_nit_add_network_name_descriptor(struct ts_nit *nit, char *network_name) {
55
+	if (!network_name || strlen(network_name) > 255)
56
+		return 0;
57
+
58
+	nit->network_info_size = strlen(network_name) + 2;
59
+
60
+	uint8_t *descriptor = calloc(1, nit->network_info_size);
61
+	int dpos = 0;
62
+	descriptor[dpos + 0] = 0x40;						// Network name descriptor
63
+	descriptor[dpos + 1] = nit->network_info_size - 2;	// -2 Because of two byte header
64
+	dpos += 2;
65
+	char *name = network_name;
66
+	while (name[0]) {
67
+		descriptor[dpos++] = name[0];
68
+		name++;
69
+	}
70
+	nit->network_info = descriptor;
71
+	nit->section_header->section_length += nit->network_info_size;
72
+
73
+	ts_nit_init_private_variables(nit);
74
+	return 1;
75
+}
76
+
77
+static int ts_nit_add_stream(struct ts_nit *nit, uint16_t ts_id, uint16_t org_net_id, uint8_t *desc, uint8_t desc_size) {
78
+	if (nit->streams_num == nit->streams_max - 1 || desc_size == 0) {
79
+		FREE(desc);
80
+		return 0;
81
+	}
82
+
83
+	int stream_len = 2 + 2 + 1 + 1 + desc_size;
84
+	if (stream_len + nit->section_header->section_length > 4093) {
85
+		ts_LOGf("NIT no space left, max 4093, current %d will become %d!\n",
86
+			nit->section_header->section_length,
87
+			stream_len + nit->section_header->section_length);
88
+		free(desc);
89
+		return 0;
90
+	}
91
+
92
+	nit->ts_loop_size                   += stream_len;
93
+	nit->section_header->section_length += stream_len;
94
+
95
+	struct ts_nit_stream *sinfo = calloc(1, sizeof(struct ts_nit_stream));
96
+	sinfo->transport_stream_id = ts_id;			// 2 bytes
97
+	sinfo->original_network_id = org_net_id;	// 2 bytes
98
+	sinfo->reserved1           = 15;			// 1 byte
99
+	sinfo->descriptor_size     = desc_size;		// 1 byte
100
+	sinfo->descriptor_data     = desc;			// desc_size bytes
101
+
102
+	nit->streams[nit->streams_num] = sinfo;
103
+	nit->streams_num++;
104
+
105
+	ts_nit_init_private_variables(nit);
106
+
107
+	return 1;
108
+}
109
+
110
+// freq_type 0 == undefined
111
+// freq_type 1 == satellite
112
+// freq_type 2 == cable
113
+// freq_type 3 == terrestrial
114
+static int ts_nit_add_frequency_list_descriptor(struct ts_nit *nit, uint16_t ts_id, uint16_t org_net_id, uint8_t freq_type, uint32_t *freqs, uint8_t num_freqs) {
115
+	uint8_t i;
116
+	if (!num_freqs || num_freqs > 63)
117
+		return 0;
118
+	int desc_size = 2 + 1 + num_freqs * 4;		// 2 for header desc header, 1 for coding type, 4 for each frequency
119
+	uint8_t *desc = calloc(1, desc_size);
120
+	int dpos = 0;
121
+	desc[dpos + 0] = 0x62;				// frequency_list_descriptor
122
+	desc[dpos + 1] = desc_size - 2;		// -2 Because of two byte header
123
+	desc[dpos + 2] = 0xfc | freq_type;	// 6 bits reserved, 2 bits freq_type
124
+	dpos += 3;
125
+	for(i=0;i<num_freqs;i++) {
126
+		uint32_t freq = freqs[i];
127
+		desc[dpos + 0] = ((freq &~ 0x00ffffff) >> 24);
128
+		desc[dpos + 1] = ((freq &~ 0xff00ffff) >> 16);
129
+		desc[dpos + 2] = ((freq &~ 0xffff00ff) >>  8);
130
+		desc[dpos + 3] =  (freq &~ 0xffffff00);
131
+		dpos += 4;
132
+	}
133
+	return ts_nit_add_stream(nit, ts_id, org_net_id, desc, desc_size);
134
+}
135
+
136
+
137
+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) {
138
+	return ts_nit_add_frequency_list_descriptor(nit, ts_id, org_net_id, 2, freqs, num_freqs);
139
+}
140
+
141
+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) {
142
+	int desc_size = 13;
143
+	uint8_t *desc = calloc(1, desc_size);
144
+	desc[ 0] = 0x44;							// cable_delivey_system_descriptor
145
+	desc[ 1] = 11;								// -2 Because of two byte header
146
+	desc[ 2] = ((freq &~ 0x00ffffff) >> 24);	// 32 bits, frequency
147
+	desc[ 3] = ((freq &~ 0xff00ffff) >> 16);
148
+	desc[ 4] = ((freq &~ 0xffff00ff) >>  8);
149
+	desc[ 5] =  (freq &~ 0xffffff00);
150
+	desc[ 6] = 0xff;								// 8 bits reserved
151
+	desc[ 7] = 0xf0;								// 4 bits reserved, 4 bits FEC_outer (0 == not defined)
152
+	desc[ 8] = modulation;							// 8 bits reserved
153
+	desc[ 9] = (symbol_rate >> 20) &~ 0xffffff00;	// 28 bits, symbol_rate
154
+	desc[10] = (symbol_rate >> 12) &~ 0xffffff00;
155
+	desc[11] = (symbol_rate >> 4 ) &~ 0xffffff00;
156
+	desc[12] = (symbol_rate &~ 0xfffffff0) << 4;	// 4 bits
157
+	desc[12] |= 0;									// 4 bits FEC_inner (0 == not defined)
158
+	return ts_nit_add_stream(nit, ts_id, org_net_id, desc, desc_size);
159
+}
160
+
161
+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) {
162
+	uint8_t i;
163
+	if (!num_services || num_services > 85) // 85 * 3 == 255
164
+		return 0;
165
+	int desc_size = 2 + num_services * 3;		// 2 for header desc header, 3 for each service
166
+	uint8_t *desc = calloc(1, desc_size);
167
+	int dpos = 0;
168
+	desc[dpos + 0] = 0x41;				// service_list_descriptor
169
+	desc[dpos + 1] = desc_size - 2;		// -2 Because of two byte header
170
+	dpos += 2;
171
+	for(i=0;i<num_services;i++) {
172
+		uint32_t srv = services[i];
173
+		desc[dpos + 0] = (srv &~ 0xff00ffff) >> 16;	// service_id (16 bits)
174
+		desc[dpos + 1] = (srv &~ 0xffff00ff) >>  8;
175
+		desc[dpos + 2] = (srv &~ 0xffffff00);		// service_type (8 bits)
176
+		dpos += 3;
177
+	}
178
+	return ts_nit_add_stream(nit, ts_id, org_net_id, desc, desc_size);
179
+}

+ 241
- 0
tsfuncs_pat.c View File

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_pat *ts_pat_alloc() {
10
+	struct ts_pat *pat = calloc(1, sizeof(struct ts_pat));
11
+	pat->section_header	= ts_section_data_alloc();
12
+	pat->programs_max	= 128;
13
+	pat->programs		= calloc(pat->programs_max, sizeof(void *));
14
+	return pat;
15
+}
16
+
17
+void ts_pat_free(struct ts_pat **ppat) {
18
+	struct ts_pat *pat = *ppat;
19
+	int i;
20
+	if (pat) {
21
+		ts_section_data_free(&pat->section_header);
22
+		for (i=0;i<pat->programs_num;i++) {
23
+			FREE(pat->programs[i]);
24
+		}
25
+		FREE(pat->programs);
26
+		FREE(*ppat);
27
+	}
28
+}
29
+
30
+static struct ts_pat *ts_pat_reset(struct ts_pat *pat) {
31
+	struct ts_pat *newpat = ts_pat_alloc();
32
+	ts_pat_free(&pat);
33
+	return newpat;
34
+}
35
+
36
+struct ts_pat *ts_pat_push_packet(struct ts_pat *pat, uint8_t *ts_packet) {
37
+	struct ts_header ts_header;
38
+	memset(&ts_header, 0, sizeof(struct ts_header));
39
+
40
+	if (ts_packet_header_parse(ts_packet, &ts_header)) {
41
+		// PAT should be with PID 0x00
42
+		if (ts_header.pid != 0x00)
43
+			goto OUT;
44
+		if (!pat->ts_header.pusi)
45
+			pat->ts_header = ts_header;
46
+	}
47
+
48
+	if (ts_header.pusi) {
49
+		struct ts_section_header section_header;
50
+		memset(&section_header, 0, sizeof(struct ts_section_header));
51
+
52
+		uint8_t *section_data = ts_section_header_parse(ts_packet, &pat->ts_header, &section_header);
53
+		if (!section_data || !section_header.section_syntax_indicator) {
54
+			memset(&pat->ts_header, 0, sizeof(struct ts_header));
55
+			goto OUT;
56
+		}
57
+		// table_id should be 0x00 (program_association_section)
58
+		if (section_header.table_id != 0x00) {
59
+			memset(&pat->ts_header, 0, sizeof(struct ts_header));
60
+			goto OUT;
61
+		}
62
+
63
+		// Set correct section_header
64
+		ts_section_header_parse(ts_packet, &pat->ts_header, pat->section_header);
65
+	}
66
+
67
+	if (!pat->initialized) {
68
+		if (pat->section_header->section_syntax_indicator) {
69
+			ts_section_add_packet(pat->section_header, &ts_header, ts_packet);
70
+			if (pat->section_header->initialized) {
71
+				if (!ts_pat_parse(pat))
72
+					goto ERROR;
73
+			}
74
+		}
75
+	}
76
+
77
+OUT:
78
+	return pat;
79
+
80
+ERROR:
81
+	return ts_pat_reset(pat);
82
+}
83
+
84
+int ts_pat_parse(struct ts_pat *pat) {
85
+	uint8_t *section_data = pat->section_header->section_data + 8; // + 8 to compensate for section table header
86
+	int section_len = pat->section_header->packet_section_len;
87
+
88
+	while (section_len > 0) {
89
+		if (pat->programs_num == pat->programs_max) {
90
+			ts_LOGf("PAT contains too many programs (>%d), not all are initialized!\n", pat->programs_max);
91
+			break;
92
+		}
93
+		struct ts_pat_program *pinfo = calloc(1, sizeof(struct ts_pat_program));
94
+
95
+		pinfo->program  = (section_data[0] << 8) | section_data[1];				// xxxxxxxx xxxxxxxx
96
+		pinfo->reserved = (section_data[2] &~ 0x1F) >> 5;						// xxx11111
97
+		pinfo->pid      = ((section_data[2] &~ 0xE0) << 8) | section_data[3];	// 111xxxxx xxxxxxxx
98
+
99
+		pat->programs[pat->programs_num] = pinfo;
100
+		pat->programs_num++;
101
+
102
+		section_data += 4;
103
+		section_len  -= 4;
104
+	}
105
+	pat->CRC = (pat->CRC << 8) | section_data[3];
106
+	pat->CRC = (pat->CRC << 8) | section_data[2];
107
+	pat->CRC = (pat->CRC << 8) | section_data[1];
108
+	pat->CRC = (pat->CRC << 8) | section_data[0];
109
+
110
+	u_int32_t check_crc = ts_crc32(pat->section_header->section_data, pat->section_header->data_size);
111
+	if (check_crc != 0) {
112
+		ts_LOGf("!!! Wrong PAT CRC! It should be 0 but it is %08x (CRC in data is 0x%08x)\n", check_crc, pat->CRC);
113
+		return 0;
114
+	}
115
+
116
+	pat->initialized = 1;
117
+	return 1;
118
+}
119
+
120
+void ts_pat_generate(struct ts_pat *pat, uint8_t **ts_packets, int *num_packets) {
121
+	uint8_t *secdata = ts_section_data_alloc_section();
122
+	ts_section_header_generate(secdata, pat->section_header, 0);
123
+	int curpos = 8; // Compensate for the section header, frist data byte is at offset 8
124
+
125
+	int i;
126
+	for (i=0;i<pat->programs_num;i++) {
127
+		struct ts_pat_program *prg = pat->programs[i];
128
+		secdata[curpos + 0] = prg->program >> 8;
129
+		secdata[curpos + 1] = prg->program &~ 0xff00;
130
+
131
+		secdata[curpos + 2]  = prg->reserved << 5;
132
+		secdata[curpos + 2] |= prg->pid >> 8;
133
+		secdata[curpos + 3]  = prg->pid &~ 0xff00;
134
+		curpos += 4; // Compensate for the above
135
+	}
136
+	pat->CRC = ts_section_data_calculate_crc(secdata, curpos);
137
+	curpos += 4; // CRC
138
+
139
+	ts_section_data_gen_ts_packets(&pat->ts_header, secdata, curpos, pat->section_header->pointer_field, ts_packets, num_packets);
140
+
141
+	FREE(secdata);
142
+}
143
+
144
+void ts_pat_regenerate_packets(struct ts_pat *pat) {
145
+	uint8_t *ts_packets;
146
+	int num_packets;
147
+	ts_pat_generate(pat, &ts_packets, &num_packets);
148
+	FREE(pat->section_header->packet_data);
149
+	pat->section_header->packet_data = ts_packets;
150
+	pat->section_header->num_packets = num_packets;
151
+}
152
+
153
+struct ts_pat *ts_pat_copy(struct ts_pat *pat) {
154
+	struct ts_pat *newpat = ts_pat_alloc();
155
+	int i;
156
+	for (i=0;i<pat->section_header->num_packets; i++) {
157
+		newpat = ts_pat_push_packet(newpat, pat->section_header->packet_data + (i * TS_PACKET_SIZE));
158
+	}
159
+	if (newpat->initialized) {
160
+		return newpat;
161
+	} else {
162
+		ts_LOGf("Error copying PAT!\n");
163
+		ts_pat_free(&newpat);
164
+		return NULL;
165
+	}
166
+}
167
+
168
+void ts_pat_check_generator(struct ts_pat *pat) {
169
+	struct ts_pat *pat1 = ts_pat_copy(pat);
170
+	if (pat1) {
171
+		ts_compare_data("PAT (tspacket->struct)",
172
+			pat1->section_header->packet_data,
173
+			pat->section_header->packet_data,
174
+			pat->section_header->num_packets * TS_PACKET_SIZE);
175
+		ts_pat_free(&pat1);
176
+	}
177
+
178
+	uint8_t *ts_packets;
179
+	int num_packets;
180
+	ts_pat_generate(pat, &ts_packets, &num_packets);
181
+	if (num_packets != pat->section_header->num_packets) {
182
+		ts_LOGf("ERROR: num_packets:%d != sec->num_packets:%d\n", num_packets, pat->section_header->num_packets);
183
+	}
184
+	ts_compare_data("PAT (struct->tspacket)", pat->section_header->packet_data, ts_packets, num_packets * TS_PACKET_SIZE);
185
+	free(ts_packets);
186
+}
187
+
188
+void ts_pat_dump(struct ts_pat *pat) {
189
+	int i;
190
+	ts_LOGf("PAT packet\n");
191
+    for(i=0;i<pat->section_header->num_packets;i++) {
192
+        struct ts_header tshdr;
193
+        ts_packet_header_parse(pat->section_header->packet_data + (i * TS_PACKET_SIZE), &tshdr);
194
+        ts_packet_header_dump(&tshdr);
195
+    }
196
+    ts_section_header_dump(pat->section_header);
197
+	ts_LOGf("  * PAT data\n");
198
+	ts_LOGf("    * num_programs: %d\n", pat->programs_num);
199
+	for (i=0;i<pat->programs_num;i++) {
200
+		struct ts_pat_program *prg = pat->programs[i];
201
+		ts_LOGf("      * [%02d/%02d]: Program No 0x%04x (%5d) -> PID %04x (%d) /res: 0x%02x/\n",
202
+			i+1, pat->programs_num,
203
+			prg->program, prg->program,
204
+			prg->pid, prg->pid,
205
+			prg->reserved);
206
+		// Program number 0 is Network ID, not program id
207
+		if (prg->program == 0) {
208
+			ts_LOGf("      - NIT PID %04x (%d)\n", prg->pid, prg->pid);
209
+		}
210
+	}
211
+	ts_LOGf("  * CRC 0x%08x\n", pat->CRC);
212
+
213
+	ts_pat_check_generator(pat);
214
+}
215
+
216
+int ts_pat_is_same(struct ts_pat *pat1, struct ts_pat *pat2) {
217
+	int i;
218
+
219
+	if (pat1->CRC == pat2->CRC) // Same
220
+		return 1;
221
+
222
+	// If some version is not current, just claim the structures are the same
223
+	if (!pat1->section_header->current_next_indicator || pat2->section_header->version_number)
224
+		return 1;
225
+
226
+	if (pat1->section_header->version_number != pat2->section_header->version_number) // Different
227
+		return 0;
228
+
229
+	if (pat1->programs_num != pat2->programs_num) // Different
230
+		return 0;
231
+
232
+	// Check each program and PIDs
233
+	for (i=0;i<pat1->programs_num;i++) {
234
+		struct ts_pat_program *prg1 = pat1->programs[i];
235
+		struct ts_pat_program *prg2 = pat2->programs[i];
236
+		if (prg1->program != prg2->program || prg1->pid != prg2->pid) // Different
237
+			return 0;
238
+	}
239
+
240
+	return 1; // Same
241
+}

+ 116
- 0
tsfuncs_pat_desc.c View File

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_pat_regenerate_packet_data(struct ts_pat *pat) {
10
+	uint8_t *ts_packets;
11
+	int num_packets;
12
+	ts_pat_generate(pat, &ts_packets, &num_packets);
13
+	memcpy(pat->section_header->packet_data, ts_packets, num_packets * TS_PACKET_SIZE);
14
+	pat->section_header->num_packets = num_packets;
15
+	free(ts_packets);
16
+}
17
+
18
+static void ts_pat_init_private_variables(struct ts_pat *pat) {
19
+	pat->section_header->data_size          = pat->section_header->section_length + 3;
20
+	pat->section_header->packet_section_len = pat->section_header->data_size - 8 - 4;	// -8 for the section header, -4 for the CRC at the end
21
+	ts_pat_regenerate_packet_data(pat);
22
+}
23
+
24
+struct ts_pat *ts_pat_alloc_init(uint16_t transport_stream_id) {
25
+	struct ts_pat *pat = ts_pat_alloc();
26
+
27
+	pat->ts_header.pid            = 0x00;
28
+	pat->ts_header.pusi           = 1;
29
+	pat->ts_header.payload_field  = 1;
30
+	pat->ts_header.payload_offset = 4;
31
+
32
+	pat->section_header->table_id                 = 0x00;
33
+	pat->section_header->version_number           = 1;
34
+	pat->section_header->current_next_indicator   = 1;
35
+	pat->section_header->section_syntax_indicator = 1;
36
+	pat->section_header->private_indicator        = 0;
37
+	pat->section_header->section_length           = 9; // Empty section (9)
38
+	pat->section_header->reserved1                = 3;
39
+	pat->section_header->reserved2                = 3;
40
+
41
+	pat->section_header->ts_id_number             = transport_stream_id;
42
+
43
+	pat->initialized = 1;
44
+
45
+	ts_pat_init_private_variables(pat);
46
+
47
+	return pat;
48
+}
49
+
50
+int ts_pat_add_program(struct ts_pat *pat, uint16_t program, uint16_t pat_pid) {
51
+	int i;
52
+	if (pat->programs_max == pat->programs_num)
53
+		return 0;
54
+
55
+	for (i=0;i<pat->programs_num;i++) {
56
+		struct ts_pat_program *prg = pat->programs[i];
57
+		if (program == prg->program) {
58
+			ts_LOGf("!!! Program 0x%04x (%d) already exists in PAT!\n", program, program);
59
+			return 0;
60
+		}
61
+	}
62
+
63
+	pat->section_header->version_number++;
64
+	pat->section_header->section_length += 4;
65
+
66
+	struct ts_pat_program *pinfo = calloc(1, sizeof(struct ts_pat_program));
67
+	pinfo->program  = program;
68
+	pinfo->reserved = 7; // All three bits are up
69
+	pinfo->pid      = pat_pid;
70
+
71
+	pat->programs[pat->programs_num] = pinfo;
72
+	pat->programs_num++;
73
+
74
+	ts_pat_init_private_variables(pat);
75
+	return 1;
76
+}
77
+
78
+int ts_pat_del_program(struct ts_pat *pat, uint16_t program) {
79
+	int i, ok=1, del_pos=0;
80
+
81
+	if (!pat->programs_num)
82
+		return 0;
83
+
84
+	for (i=0;i<pat->programs_num;i++) {
85
+		struct ts_pat_program *prg = pat->programs[i];
86
+		if (program == prg->program) {
87
+			ts_LOGf("!!! Found program 0x%04x (%d) for deleting.\n", program, program);
88
+			del_pos = i;
89
+			ok = 1;
90
+			break;
91
+		}
92
+	}
93
+
94
+	if (!ok)
95
+		return 0;
96
+
97
+	for (i=0;i<pat->programs_num;i++) {
98
+		if (i < del_pos)
99
+			continue;
100
+		if (i == del_pos) {
101
+			FREE(pat->programs[i]);
102
+		}
103
+		if (i >= del_pos && i+1 < pat->programs_num) {
104
+			struct ts_pat_program *next = pat->programs[i+1];
105
+			pat->programs[i] = next;
106
+		}
107
+	}
108
+
109
+	pat->section_header->version_number++;
110
+	pat->section_header->section_length -= 4;
111
+	pat->programs_num--;
112
+
113
+	ts_pat_init_private_variables(pat);
114
+
115
+	return 1;
116
+}

+ 39
- 0
tsfuncs_pat_test.c View File

1
+
2
+void ts_test_pat() {
3
+	struct ts_pat *pat = ts_pat_init_empty();
4
+
5
+	ts_pat_dump(pat);
6
+	ts_pat_check_generator(pat, 0);
7
+
8
+	ts_pat_add_program(pat, 1, 0x100);
9
+	ts_pat_dump(pat);
10
+/*
11
+//	ts_pat_check_generator(pat);
12
+
13
+	struct ts_pat *pat1 = calloc(1, sizeof(struct ts_pat));
14
+
15
+	ts_pat_init(pat1, pat->packet_data);
16
+	ts_pat_dump(pat1);
17
+	ts_pat_free(pat1);
18
+*/
19
+/*
20
+	ts_pat_add_program(pat, 1, 0x100);
21
+	ts_pat_add_program(pat, 2, 0x100);
22
+	ts_pat_add_program(pat, 3, 0x100);
23
+	ts_pat_dump(pat);
24
+	ts_pat_check_generator(pat);
25
+
26
+	ts_pat_del_program(pat, 3);
27
+	ts_pat_dump(pat);
28
+	ts_pat_check_generator(pat);
29
+
30
+//	int i;
31
+//	for (i=0;i<10;i++) {
32
+//		ts_pat_add_program(pat, i+10, (i+5)*10);
33
+//	}
34
+
35
+	ts_pat_dump(pat);
36
+	ts_pat_check_generator(pat);
37
+*/
38
+	ts_pat_free(pat);
39
+}

+ 544
- 0
tsfuncs_pes.c View File

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
+#define pes_data_size_buffer (1024)
10
+#define pes_max_data_size    (1024*1024)
11
+
12
+struct ts_pes *ts_pes_alloc() {
13
+	struct ts_pes *pes = calloc(1, sizeof(struct ts_pes));
14
+	pes->pes_data_size = pes_data_size_buffer;
15
+	pes->pes_data = malloc(pes->pes_data_size);
16
+	memset(pes->pes_data, 0x33, pes->pes_data_size);
17
+	return pes;
18
+}
19
+
20
+void ts_pes_free(struct ts_pes **ppes) {
21
+	struct ts_pes *pes = *ppes;
22
+	if (pes) {
23
+		FREE(pes->pes_data);
24
+		FREE(*ppes);
25
+	}
26
+}
27
+
28
+struct ts_pes *ts_pes_reset(struct ts_pes *pes) {
29
+	uint8_t *pes_data = pes->pes_data;
30
+	uint32_t pes_data_size = pes->pes_data_size;
31
+	memset(pes, 0, sizeof(struct ts_pes));
32
+	pes->pes_data = pes_data;
33
+	pes->pes_data_size = pes_data_size;
34
+	return pes;
35
+}
36
+
37
+static void ts_pes_add_payload_to_pes_data(struct ts_pes *pes, uint8_t *payload, uint8_t payload_size) {
38
+	uint32_t new_data_pos = pes->pes_data_pos + payload_size;
39
+	// Check if there is enough space in pes->pes_data
40
+	if (new_data_pos > pes->pes_data_size) {
41
+		int old_data_size = pes->pes_data_size;
42
+		pes->pes_data_size *= 2;
43
+//		ts_LOGf("realloc to %d from %d\n", old_data_size, pes->pes_data_size);
44
+		pes->pes_data = realloc(pes->pes_data, pes->pes_data_size);
45
+		// Poison
46
+		memset(pes->pes_data + pes->pes_data_pos, 0x34, pes->pes_data_size - old_data_size);
47
+	}
48
+	memcpy(pes->pes_data + pes->pes_data_pos, payload, payload_size);
49
+	pes->pes_data_pos += payload_size;
50
+	if (pes->pes_packet_len) {
51
+		// If packet size is known, mark the packet as initialized
52
+		if (pes->pes_data_pos >= pes->pes_packet_len) {
53
+			pes->pes_data_initialized = 1;
54
+		}
55
+	}
56
+}
57
+
58
+// This function is used to determine the last PES was finished before current ts_packet
59
+int ts_pes_is_finished(struct ts_pes *pes, uint8_t *ts_packet) {
60
+	if (pes->pes_data_initialized)
61
+		return 1;
62
+
63
+	// Time to mark PES as initialized since current packet has PUSI
64
+	if (ts_packet_is_pusi(ts_packet) && pes->real_pes_packet_len == -1) {
65
+		pes->real_pes_packet_len = pes->pes_data_pos;
66
+		pes->pes_data_initialized = 1;
67
+//		ts_LOGf("packet finished, len:%d\n", pes->real_pes_packet_len);
68
+		if (!ts_pes_parse(pes)) {
69
+			ts_LOGf("error parsing!\n");
70
+			pes = ts_pes_reset(pes);
71
+			return 0;
72
+		}
73
+//		ts_LOGf("parsed OK!\n");
74
+		return 1;
75
+	}
76
+
77
+	return 0;
78
+}
79
+
80
+// Fill is_video, is_audio, is_ac3, etc..flags in PES packet
81
+void ts_pes_fill_type(struct ts_pes *pes, struct ts_pmt *pmt, uint16_t pid) {
82
+	int i;
83
+	pes->is_audio = IS_AUDIO_STREAM_ID(pes->stream_id);
84
+	pes->is_video = IS_VIDEO_STREAM_ID(pes->stream_id);
85
+	if (pmt && pmt->initialized) {
86
+		for (i=0;i<pmt->streams_num;i++) {
87
+			struct ts_pmt_stream *stream = pmt->streams[i];
88
+			if (stream->pid != pid)
89
+				continue;
90
+
91
+			pes->is_audio       = pes->is_audio && ts_is_stream_type_audio(stream->stream_type);
92
+			pes->is_audio_mpeg1 = pes->is_audio && stream->stream_type == STREAM_TYPE_MPEG1_AUDIO;
93
+			pes->is_audio_mpeg2 = pes->is_audio && stream->stream_type == STREAM_TYPE_MPEG2_AUDIO;
94
+			// To determine if type is AC3 we need to check descriptors
95
+			//pes->is_audio_ac3   = ts_is_stream_type_ac3(stream->stream_type); // We need to also check descriptors because this is not ENOUGH!
96
+			pes->is_audio_aac   = pes->is_audio && stream->stream_type == STREAM_TYPE_ADTS_AUDIO;
97
+
98
+			pes->is_video       = pes->is_video && ts_is_stream_type_video(stream->stream_type);
99
+			pes->is_video_mpeg1 = pes->is_video && stream->stream_type == STREAM_TYPE_MPEG1_VIDEO;
100
+			pes->is_video_mpeg2 = pes->is_video && stream->stream_type == STREAM_TYPE_MPEG2_VIDEO;
101
+			pes->is_video_mpeg4 = pes->is_video && stream->stream_type == STREAM_TYPE_MPEG4_PART2_VIDEO;
102
+			pes->is_video_h264  = pes->is_video && stream->stream_type == STREAM_TYPE_AVC_VIDEO;
103
+			pes->is_video_avs   = pes->is_video && stream->stream_type == STREAM_TYPE_AVS_VIDEO;
104
+
105
+			if (!stream->ES_info)
106
+				break;
107
+
108
+			// Parse stream descriptors to gather more information
109
+			uint8_t tag, this_length;
110
+			uint8_t *data = stream->ES_info;
111
+			int data_len = stream->ES_info_size;
112
+			while (data_len >= 2) {
113
+				tag         = data[0];
114
+				this_length = data[1];
115
+				data       += 2;
116
+				data_len   -= 2;
117
+				if (this_length > data_len) {
118
+					// Not much we can do! Give up.
119
+					ts_LOGf("!!! Descriptor 0x%02x says length %d, but only %d bytes left\n", tag, this_length, data_len);
120
+					break;
121
+				}
122
+				switch (tag) {
123
+					case  3: { // Audio stream descriptor
124
+						struct {
125
+							uint8_t free_format_flag : 1,
126
+							        ID               : 1,
127
+							        layer            : 2,
128
+							        vbr_flag         : 1,
129
+							        reserved         : 3;
130
+						} as;
131
+						if (this_length >= 1) {
132
+							as.free_format_flag = bit_on(data[0], bit_8);
133
+							as.ID               = bit_on(data[0], bit_7);
134
+							as.layer            = (data[0] &~ 0xcf) >> 4;	// 11xx1111
135
+							as.vbr_flag         = bit_on(data[0], bit_4);
136
+							as.reserved         = data[0] &~ 0xf0;			// 1111xxxx
137
+							if (as.ID) {
138
+								pes->is_audio = 1;
139
+								pes->is_audio_mpeg1l1 = as.layer == 3;
140
+								pes->is_audio_mpeg1l2 = as.layer == 2;
141
+								pes->is_audio_mpeg1l3 = as.layer == 1;
142
+							}
143
+						}
144
+						break;
145
+					}
146
+					case  5: { // Registration descriptor
147
+						if (this_length == 4) {
148
+							uint32_t reg_ident  = data[0] << 24;
149
+							reg_ident          |= data[1] << 16;
150
+							reg_ident          |= data[2] << 8;
151
+							reg_ident          |= data[3];
152
+							// See http://smpte-ra.org/mpegreg/mpegreg.html
153
+							if (reg_ident == 0x41432D33) { // AC-3
154
+								pes->is_audio = 1;
155
+								pes->is_audio_ac3 = 1;
156
+								//ts_LOGf("reg_desc says AC-3\n");
157
+							}
158
+							if (reg_ident == 0x44545331 || reg_ident == 0x44545332 || reg_ident == 0x44545333) { // DTS1, DTS2, DTS2
159
+								pes->is_audio = 1;
160
+								pes->is_audio_dts = 1;
161
+								//ts_LOGf("reg_desc says DTSx\n");
162
+							}
163
+						}
164
+						break;
165
+					}
166
+					case 0x6a: { // AC-3 descriptor
167
+						//ts_LOGf("ac3_desc found\n");
168
+						pes->is_audio = 1;
169
+						pes->is_audio_ac3 = 1;
170
+						break;
171
+					}
172
+					case 0x7b: { // DTS descriptor
173
+						//ts_LOGf("ac3_desc found\n");
174
+						pes->is_audio = 1;
175
+						pes->is_audio_dts = 1;
176
+						break;
177
+					}
178
+					case 0x56: { // teletext
179
+						//ts_LOGf("teletext_desc found\n");
180
+						pes->is_teletext = 1;
181
+						break;
182
+					}
183
+					case 0x59: { // Subtitling descriptor
184
+						//ts_LOGf("subtitle_desc found\n");
185
+						pes->is_subtitle = 1;
186
+						break;
187
+					}
188
+				} // switch
189
+				data_len -= this_length;
190
+				data += this_length;
191
+			} // while
192
+		}
193
+	}
194
+}
195
+
196
+struct ts_pes *ts_pes_push_packet(struct ts_pes *pes, uint8_t *ts_packet, struct ts_pmt *pmt, uint16_t pid) {
197
+	struct ts_header ts_header;
198
+	memset(&ts_header, 0, sizeof(struct ts_header));
199
+
200
+	uint8_t *payload = ts_packet_header_parse(ts_packet, &ts_header);
201
+	uint8_t payload_size = ts_header.payload_size;
202
+
203
+	if (!payload || !payload_size)
204
+		goto OUT;
205
+
206
+	if (ts_header.pusi) {
207
+		uint8_t stream_id = 0;
208
+		int pes_packet_len = 0;
209
+		if (payload[0] == 0x00 && payload[1] == 0x00 && payload[2] == 0x01) { // pes_start_code_prefix
210
+			pes->ts_header = ts_header;
211
+			stream_id = payload[3];
212
+			pes_packet_len = (payload[4] << 8) | payload[5];
213
+//			ts_LOGf("NEW PES. Stream_id=%02x pes_length=%d\n", stream_id, pes_packet_len);
214
+			if (pes_packet_len == 0 && pes->real_pes_packet_len == -1) {
215
+				ts_LOGf("!!! ERROR: New pes with pes_packed_len == 0, started before the old was finished\n");
216
+				goto ERROR;
217
+			}
218
+			if (pes_packet_len > 0) {
219
+				pes->real_pes_packet_len = pes_packet_len;
220
+			} else {
221
+				pes->real_pes_packet_len = -1;
222
+			}
223
+			pes->stream_id = stream_id;
224
+			pes->pes_packet_len = pes_packet_len;
225
+			ts_pes_fill_type(pes, pmt, pid);
226
+		} else {
227
+			ts_LOGf("!!! PES_start_code_prefix not found. Expected 0x00 0x00 0x01 but get 0x%02x 0x%02x 0x%02x! PID %03x\n",
228
+				payload[0], payload[1], payload[2], ts_header.pid);
229
+			goto ERROR;
230
+		}
231
+	}
232
+
233
+	if (pes->stream_id) {
234
+		ts_pes_add_payload_to_pes_data(pes, payload, payload_size);
235
+//		ts_LOGf("Payload %d added, tot_size: %d\n", payload_size, pes->pes_data_pos);
236
+		if (pes->pes_data_pos > pes_max_data_size) {
237
+			ts_LOGf("PES Payload size %d exceeded pes_data_max_size: %d pid: %03x\n",
238
+				pes->pes_data_pos, pes_max_data_size, pes->ts_header.pid);
239
+			goto ERROR;
240
+		}
241
+	}
242
+
243
+	if (pes->pes_data_initialized) {
244
+		if (!ts_pes_parse(pes))
245
+			goto ERROR;
246
+	}
247
+
248
+OUT:
249
+	return pes;
250
+
251
+ERROR:
252
+	return ts_pes_reset(pes);
253
+}
254
+
255
+int ts_pes_parse(struct ts_pes *pes) {
256
+	uint8_t *data = pes->pes_data;
257
+
258
+	if (!pes->pes_data_initialized) {
259
+		ts_LOGf("!!! pes_data_initialized not true\n");
260
+		return 0;
261
+	}
262
+
263
+	if (pes->real_pes_packet_len == -1) {
264
+		ts_LOGf("!!! real_pes_data_len is == -1\n");
265
+		return 0;
266
+	}
267
+
268
+	if (pes->pes_data_size < 6) {
269
+		ts_LOGf("!!! PES data_size < 6\n");
270
+		return 0;
271
+	}
272
+
273
+	if (!(data[0] == 0x00 && data[1] == 0x00 && data[2] == 0x01)) { // pes_start_code_prefix
274
+		ts_LOGf("!!! PES_start_code_prefix error! Expected 0x00 0x00 0x01 but get 0x%02x 0x%02x 0x%02x! PID %03x\n",
275
+			data[0], data[1], data[2], pes->ts_header.pid);
276
+		return 0;
277
+	}
278
+
279
+	pes->stream_id      = data[3];						// 8 bits
280
+	pes->pes_packet_len = (data[4] << 8) | data[5];		// 16 bits
281
+	int dpos = 6;
282
+
283
+	if (!IS_PES_STREAM_SUPPORTED(pes->stream_id)) {
284
+		// We do not handle this streams...
285
+		ts_LOGf("!!! Unsupported stream, ignore! (%02x) PID %03x\n", pes->stream_id, pes->ts_header.pid);
286
+		return 0;
287
+	}
288
+
289
+	dpos = 6;
290
+	if ((data[dpos] &~ 0x3f) != 0x80) {		// 10xxxxxx (first two bits must be 10 eq 0x80
291
+		ts_LOGf("!!! No 10 bits at PES start, expected 0x80 get 0x%02x, org: %02x! PID %03x\n",
292
+			data[dpos] &~ 0x3f, data[dpos], pes->ts_header.pid);
293
+		return 0;
294
+	}
295
+	// data[dpos] = 0xff;
296
+	pes->flags_1			= data[dpos];
297
+	pes->scrambling			= (data[dpos] &~ 0xCF) >> 4;
298
+	pes->priority			= bit_on(data[dpos], bit_4);
299
+	pes->data_alignment		= bit_on(data[dpos], bit_3);
300
+	pes->copyright			= bit_on(data[dpos], bit_2);
301
+	pes->original_or_copy	= bit_on(data[dpos], bit_1);
302
+
303
+	dpos = 7;
304
+	// data[dpos] = 0xff;
305
+	pes->flags_2			= data[dpos];
306
+	pes->PTS_flag			= bit_on(data[dpos], bit_8);
307
+	pes->DTS_flag			= bit_on(data[dpos], bit_7);
308
+	pes->ESCR_flag			= bit_on(data[dpos], bit_6);
309
+	pes->ES_rate_flag		= bit_on(data[dpos], bit_5);
310
+	pes->trick_mode_flag	= bit_on(data[dpos], bit_4);
311
+	pes->add_copy_info_flag	= bit_on(data[dpos], bit_3);
312
+	pes->pes_crc_flag		= bit_on(data[dpos], bit_2);
313
+	pes->pes_extension_flag	= bit_on(data[dpos], bit_1);
314
+	dpos = 8;
315
+
316
+	pes->pes_header_len		= data[dpos];
317
+	dpos = 9;
318
+
319
+	if (!pes->PTS_flag && pes->DTS_flag)	// Invalid, can't have only DTS flag
320
+		return 0;
321
+
322
+	if (pes->PTS_flag && !pes->DTS_flag) {
323
+		if (!ts_decode_pts_dts(&data[dpos], 2, &pes->PTS))
324
+			return 0;
325
+		dpos += 5;
326
+		pes->have_pts = 1;
327
+	}
328
+
329
+	if (pes->PTS_flag && pes->DTS_flag) {
330
+		if (!ts_decode_pts_dts(&data[dpos], 3, &pes->PTS))
331
+			return 0;
332
+		pes->have_pts = 1;
333
+		dpos += 5;
334
+
335
+		if (!ts_decode_pts_dts(&data[dpos], 1, &pes->DTS))
336
+			return 0;
337
+		pes->have_dts = 1;
338
+		dpos += 5;
339
+	}
340
+
341
+	if (pes->ESCR_flag) {
342
+		uint64_t ESCR_base;
343
+		uint32_t ESCR_extn;
344
+		ESCR_base = (data[dpos+4] >>  3) |
345
+					(data[dpos+3] <<  5) |
346
+					(data[dpos+2] << 13) |
347
+					(data[dpos+1] << 20) |
348
+				((((uint64_t)data[dpos]) & 0x03) << 28) |
349
+				((((uint64_t)data[dpos]) & 0x38) << 27);
350
+		ESCR_extn = (data[dpos+5] >> 1) | (data[dpos+4] << 7);
351
+		pes->ESCR = ESCR_base * 300 + ESCR_extn;
352
+		dpos += 6;
353
+	}
354
+
355
+	if (pes->ES_rate_flag) {
356
+		// Not decoded...
357
+		dpos += 3;
358
+	}
359
+
360
+	if (pes->trick_mode_flag) {
361
+		// Not decoded...
362
+		dpos += 1;
363
+	}
364
+
365
+	if (pes->add_copy_info_flag) {
366
+		// Not decoded...
367
+		dpos += 1;
368
+	}
369
+
370
+	if (pes->pes_crc_flag) {
371
+		// Not decoded...
372
+		dpos += 2;
373
+	}
374
+
375
+	if (pes->pes_extension_flag) {
376
+		// data[dpos] = 0xff;
377
+		pes->flags_3							= data[dpos];
378
+		pes->pes_private_data_flag				= bit_on(data[dpos], bit_8);	// 1xxxxxxx
379
+		pes->pack_header_field_flag				= bit_on(data[dpos], bit_7);	// x1xxxxxx
380
+		pes->program_packet_seq_counter_flag	= bit_on(data[dpos], bit_6);	// xx1xxxxx
381
+		pes->p_std_buffer_flag					= bit_on(data[dpos], bit_5);	// xxx1xxxx
382
+		pes->reserved2							= (data[dpos] &~ 0x0e) >> 1;	// xxxx111x
383
+		pes->pes_extension2_flag				= bit_on(data[dpos], bit_1);	// xxxxxxx1
384
+
385
+		if (pes->pes_private_data_flag) {
386
+			pes->pes_private_data_1 = (pes->pes_private_data_1 << 8) | data[dpos+7];
387
+			pes->pes_private_data_1 = (pes->pes_private_data_1 << 8) | data[dpos+6];
388
+			pes->pes_private_data_1 = (pes->pes_private_data_1 << 8) | data[dpos+5];
389
+			pes->pes_private_data_1 = (pes->pes_private_data_1 << 8) | data[dpos+4];
390
+			pes->pes_private_data_1 = (pes->pes_private_data_1 << 8) | data[dpos+3];
391
+			pes->pes_private_data_1 = (pes->pes_private_data_1 << 8) | data[dpos+2];
392
+			pes->pes_private_data_1 = (pes->pes_private_data_1 << 8) | data[dpos+1];
393
+			pes->pes_private_data_1 = (pes->pes_private_data_1 << 8) | data[dpos+0];
394
+			dpos += 8;
395
+			pes->pes_private_data_2 = (pes->pes_private_data_2 << 8) | data[dpos+7];
396
+			pes->pes_private_data_2 = (pes->pes_private_data_2 << 8) | data[dpos+6];
397
+			pes->pes_private_data_2 = (pes->pes_private_data_2 << 8) | data[dpos+5];
398
+			pes->pes_private_data_2 = (pes->pes_private_data_2 << 8) | data[dpos+4];
399
+			pes->pes_private_data_2 = (pes->pes_private_data_2 << 8) | data[dpos+3];
400
+			pes->pes_private_data_2 = (pes->pes_private_data_2 << 8) | data[dpos+2];
401
+			pes->pes_private_data_2 = (pes->pes_private_data_2 << 8) | data[dpos+1];
402
+			pes->pes_private_data_2 = (pes->pes_private_data_2 << 8) | data[dpos+0];
403
+			dpos += 8;
404
+		}
405
+
406
+		if (pes->pack_header_field_flag) {
407
+			pes->pack_header_len = data[dpos];
408
+			pes->pack_header = pes->pes_data + 1 + dpos;	// Pointer into *pes_data
409
+			dpos += 1 + pes->pack_header_len;
410
+		}
411
+
412
+		if (pes->program_packet_seq_counter_flag) {
413
+			// Not decoded
414
+			dpos += 2;
415
+		}
416
+
417
+		if (pes->p_std_buffer_flag) {
418
+			if ((data[dpos] &~ 0x3f) != 0x40) {		// 01xxxxxx (first two bits must be 01 eq 0x40
419
+				return 0;
420
+			}
421
+			// Not decoded...
422
+			dpos += 2;
423
+		}
424
+
425
+		if (pes->pes_extension2_flag) {
426
+			pes->pes_extension_field_len = data[dpos] &~ 0x80;		// x1111111
427
+			pes->pes_extension2 = pes->pes_data + 1 + dpos;	// Pointer into *pes_data
428
+			dpos += 1 + pes->pes_extension_field_len;
429
+		}
430
+	}
431
+
432
+	int maxstuffing = 32; // Maximum 32 stuffing bytes
433
+	// Skip stuffing bytes (8 is minimum PES header len)
434
+	while ((--maxstuffing > 0) && (dpos-8 <= pes->pes_header_len) && (data[dpos] == 0xff)) {
435
+		dpos++;
436
+	}
437
+
438
+	pes->es_data      = pes->pes_data + dpos;
439
+	pes->es_data_size = pes->real_pes_packet_len - dpos;
440
+	pes->initialized  = 1;
441
+
442
+	if (pes->data_alignment)
443
+		ts_pes_es_parse(pes);
444
+
445
+	return 1;
446
+}
447
+
448
+#define min(a,b) ((a < b) ? a : b)
449
+
450
+void ts_pes_dump(struct ts_pes *pes) {
451
+	if (!pes->initialized)
452
+		return;
453
+	ts_LOGf("PES packet\n");
454
+	ts_packet_header_dump(&pes->ts_header);
455
+	ts_LOGf("  * Content    : %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
456
+		pes->is_audio			? "Audio "		: "",
457
+		pes->is_audio_mpeg1		? "MP1 "		: "",
458
+		pes->is_audio_mpeg1l1	? "Layer1 "		: "",
459
+		pes->is_audio_mpeg1l2	? "Layer2 "		: "",
460
+		pes->is_audio_mpeg1l3	? "Layer3 "		: "",
461
+		pes->is_audio_mpeg2		? "MP2 "		: "",
462
+		pes->is_audio_aac		? "AAC "		: "",
463
+		pes->is_audio_ac3		? "AC3 "		: "",
464
+		pes->is_audio_dts		? "DTS "		: "",
465
+		pes->is_video			? "Video "		: "",
466
+		pes->is_video_mpeg1		? "MPEG1 "		: "",
467
+		pes->is_video_mpeg2		? "MPEG2 "		: "",
468
+		pes->is_video_mpeg4		? "MPEG4p2 "	: "",
469
+		pes->is_video_h264		? "H.264 "		: "",
470
+		pes->is_video_avs		? "AVS "		: "",
471
+		pes->is_teletext		? "Teletext "	: "",
472
+		pes->is_subtitle		? "Subtitles "	: ""
473
+	);
474
+	char *stream_id_text = h222_stream_id_desc(pes->stream_id);
475
+	ts_LOGf("  * Stream_id  : 0x%02x (%d) %s\n", pes->stream_id, pes->stream_id, stream_id_text);
476
+	FREE(stream_id_text);
477
+	ts_LOGf("  * Packet len : 0x%04x (%d) real_len: %d %s\n",
478
+		pes->pes_packet_len, pes->pes_packet_len, pes->real_pes_packet_len-pes->pes_header_len-6, pes->is_video ? "VIDEO" : (pes->is_audio ? "AUDIO" : "OTHER"));
479
+	ts_LOGf("  * Header len : %d\n", pes->pes_header_len);
480
+	ts_LOGf("  * Flags 1    : 0x%02x | scrambling=%d priority=%d data_align=%d copyright=%d org_or_copy=%d\n",
481
+		pes->flags_1,
482
+		pes->scrambling,
483
+		pes->priority,
484
+		pes->data_alignment,
485
+		pes->copyright,
486
+		pes->original_or_copy
487
+	);
488
+	ts_LOGf("  * Flags 2    : 0x%02x | %s%s%s%s%s%s%s%s\n",
489
+		pes->flags_2,
490
+		pes->PTS_flag			? "PTS "		: "",
491
+		pes->DTS_flag			? "DTS "		: "",
492
+		pes->ESCR_flag			? "ESCR "		: "",
493
+		pes->ES_rate_flag		? "ES_rate "	: "",
494
+		pes->trick_mode_flag	? "Trick_mode "	: "",
495
+		pes->add_copy_info_flag	? "Add_copy "	: "",
496
+		pes->pes_crc_flag		? "PES_CRC "	: "",
497
+		pes->pes_extension_flag	? "PES_Ext "	: ""
498
+	);
499
+	if (pes->PTS_flag && pes->have_pts)
500
+		ts_LOGf("  * PTS        : %llu\n", pes->PTS);
501
+	if (pes->DTS_flag && pes->have_dts)
502
+		ts_LOGf("  * DTS        : %llu\n", pes->DTS);
503
+	if (pes->ESCR_flag)
504
+		ts_LOGf("  * ESCR       : %llu\n", pes->ESCR);
505
+	if (pes->ES_rate_flag)
506
+		ts_LOGf("  * ES_rate    : %lu\n" , (unsigned long)pes->ES_rate * 50); // In units of 50 bytes
507
+
508
+	if (pes->pes_extension_flag) {
509
+		ts_LOGf("  * Ext flags  : 0x%02x | %s%s%s%s%s\n",
510
+			pes->flags_3,
511
+			pes->pes_private_data_flag				? "Private_data_flag "	: "",
512
+			pes->pack_header_field_flag				? "Pack_header_flag "	: "",
513
+			pes->program_packet_seq_counter_flag	? "Prg_pack_seq_flag "	: "",
514
+			pes->p_std_buffer_flag					? "P-STD_buf_flag "		: "",
515
+			pes->pes_extension2_flag				? "Ext2_flag "			: ""
516
+		);
517
+	}
518
+
519
+	if (pes->pes_private_data_flag)
520
+		ts_LOGf("  * PES priv_data : 0x%08llx%08llx\n", pes->pes_private_data_1, pes->pes_private_data_2);
521
+
522
+	if (pes->pack_header_field_flag) {
523
+		ts_LOGf("  * Pack_header ... \n");
524
+	}
525
+
526
+	if (pes->program_packet_seq_counter_flag) {
527
+		ts_LOGf("  * Prg_seq_cnt : %d\n", pes->program_packet_seq_counter);
528
+	}
529
+
530
+	ts_LOGf("  - Private    : pes_data_pos:%u es_data_size:%u\n",
531
+		pes->pes_data_pos,
532
+		pes->es_data_size
533
+	);
534
+
535
+	char *phex = ts_hex_dump(pes->pes_data, min(32, pes->pes_data_pos));
536
+	ts_LOGf("  - PES dump   : %s...\n", phex);
537
+	free(phex);
538
+
539
+	if (pes->es_data) {
540
+		char *hex = ts_hex_dump(pes->es_data, min(32, pes->es_data_size));
541
+		ts_LOGf("  - ES dump    : %s...\n", hex);
542
+		free(hex);
543
+	}
544
+}

+ 147
- 0
tsfuncs_pes_data.c View File

1
+#include <stdlib.h>
2
+#include <string.h>
3
+
4
+#include "tsdata.h"
5
+#include "tsfuncs.h"
6
+
7
+#define START_ENTRIES 1
8
+#define ENTRIES_INCREMENT 1
9
+
10
+static struct pes_entry *pes_entry_alloc(uint16_t pid) {
11
+	//ts_LOGf("Alloc pes_entry pid = %03x\n", pid);
12
+	struct pes_entry *e = malloc(sizeof(struct pes_entry));
13
+	e->pid = pid;
14
+	e->pes = ts_pes_alloc();
15
+	e->pes_next = NULL;
16
+	return e;
17
+}
18
+
19
+static void pes_entry_free(struct pes_entry **pentry) {
20
+	struct pes_entry *entry = *pentry;
21
+	if (entry) {
22
+		ts_pes_free(&entry->pes);
23
+		ts_pes_free(&entry->pes_next);
24
+		FREE(*pentry);
25
+	}
26
+}
27
+
28
+static struct pes_entry *pes_entry_find(struct pes_array *pa, uint16_t pid) {
29
+	int i;
30
+	for (i=0;i<pa->max;i++) {
31
+		struct pes_entry *e = pa->entries[i];
32
+		if (e && e->pid == pid) {
33
+			return e;
34
+		}
35
+	}
36
+	return NULL;
37
+}
38
+
39
+
40
+
41
+struct pes_array *pes_array_alloc() {
42
+	struct pes_array *pa = calloc(1, sizeof(struct pes_array));
43
+	pa->max = START_ENTRIES;
44
+	pa->entries = calloc(sizeof(struct pes_entry *), pa->max);
45
+	return pa;
46
+}
47
+
48
+struct pes_array *pes_array_realloc(struct pes_array *pa) {
49
+	pa->max += ENTRIES_INCREMENT;
50
+	pa->entries = realloc(pa->entries, sizeof(struct pes_entry *) * pa->max);
51
+	memset(&pa->entries[pa->cur], 0, sizeof(struct pes_entry *) * ((pa->max-1) - pa->cur));
52
+	return pa;
53
+}
54
+
55
+void pes_array_dump(struct pes_array *pa) {
56
+	int i;
57
+	ts_LOGf("pa->max=%d\n", pa->max);
58
+	ts_LOGf("pa->cur=%d\n", pa->cur);
59
+	for (i=0;i<pa->max;i++) {
60
+		ts_LOGf("pa->entry[%d]=0x%p\n", i, pa->entries[i]);
61
+		if (pa->entries[i]) {
62
+			ts_LOGf("pa->entry[%d]->pid=%03x\n", i, pa->entries[i]->pid);
63
+			ts_LOGf("pa->entry[%d]->pes=%p\n", i, pa->entries[i]->pes);
64
+			ts_pes_dump(pa->entries[i]->pes);
65
+		}
66
+	}
67
+}
68
+
69
+void pes_array_free(struct pes_array **ppa) {
70
+	int i;
71
+	struct pes_array *pa = *ppa;
72
+	if (pa) {
73
+		for (i=0;i<pa->max;i++) {
74
+			pes_entry_free(&pa->entries[i]);
75
+		}
76
+		free(pa->entries);
77
+		FREE(*ppa);
78
+	}
79
+}
80
+
81
+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) {
82
+	int i;
83
+
84
+	if (ts_is_psi_pid(pid, pat))
85
+		return NULL;
86
+
87
+	struct pes_entry *p = pes_entry_find(pa, pid); // Find existing entry
88
+	if (!p) { // New entry!
89
+		int pes_carrying_pid = 0; // check if PID is mentioned in PMT
90
+		for (i=0;i<pmt->streams_num;i++) {
91
+			struct ts_pmt_stream *stream = pmt->streams[i];
92
+			// Stream_type 0x80..0xff - user private
93
+			// Stream_type 0x05       - private sections
94
+			if (stream->pid == pid) {
95
+				switch (stream->stream_type) {
96
+					case 0x01: // return "11172-2 video (MPEG-1)";
97
+					case 0x02: // return "H.262/13818-2 video (MPEG-2) or 11172-2 constrained video";
98
+					case 0x03: // return "11172-3 audio (MPEG-1)";
99
+					case 0x04: // return "13818-3 audio (MPEG-2)";
100
+					case 0x06: // return "H.222.0/13818-1 PES private data";
101
+					case 0x07: // return "13522 MHEG";
102
+					case 0x08: // return "H.222.0/13818-1 Annex A - DSM CC";
103
+					case 0x09: // return "H.222.1";
104
+					case 0x0A: // return "13818-6 type A";
105
+					case 0x0B: // return "13818-6 type B";
106
+					case 0x0C: // return "13818-6 type C";
107
+					case 0x0D: // return "13818-6 type D";
108
+					case 0x0E: // return "H.222.0/13818-1 auxiliary";
109
+					case 0x0F: // return "13818-7 Audio with ADTS transport syntax";
110
+					case 0x10: // return "14496-2 Visual (MPEG-4 part 2 video)";
111
+					case 0x11: // return "14496-3 Audio with LATM transport syntax (14496-3/AMD 1)";
112
+					case 0x15: // return "Metadata in PES packets";
113
+					case 0x1B: // return "H.264/14496-10 video (MPEG-4/AVC)";
114
+					case 0x42: // return "AVS Video";
115
+						pes_carrying_pid = 1;
116
+				}
117
+				break;
118
+			}
119
+		}
120
+		if (!pes_carrying_pid) // We are not interrested
121
+			return NULL;
122
+
123
+		if (pa->cur >= pa->max) // Is there enough space in pes_array
124
+			pa = pes_array_realloc(pa); // Try to get some more
125
+
126
+		p = pes_entry_alloc(pid);
127
+		pa->entries[pa->cur++] = p;
128
+	}
129
+
130
+	// Last packet finished video PES and we saved it here
131
+	if (p->pes_next) {
132
+		ts_pes_free(&p->pes);
133
+		p->pes = p->pes_next;
134
+		p->pes_next = NULL;
135
+	}
136
+
137
+	// Video PES packets have unknown size, so we need to look one packet in the
138
+	// future to know when video PES is finished.
139
+	if (ts_pes_is_finished(p->pes, ts_packet)) {
140
+		p->pes_next = ts_pes_alloc();
141
+		p->pes_next = ts_pes_push_packet(p->pes_next, ts_packet, pmt, pid);
142
+	} else {
143
+		p->pes = ts_pes_push_packet(p->pes, ts_packet, pmt, pid);
144
+	}
145
+
146
+	return p;
147
+}

+ 130
- 0
tsfuncs_pes_es.c View File

1
+#include <netdb.h>
2
+#include <string.h>
3
+
4
+#include "tsfuncs.h"
5
+
6
+int ts_pes_es_mpeg_audio_header_parse(struct mpeg_audio_header *mpghdr, uint8_t *data, int datasz) {
7
+	if (datasz < 4)
8
+		return 0;
9
+
10
+	uint8_t d1 = data[0];
11
+	uint8_t d2 = data[1];
12
+	uint8_t d3 = data[2];
13
+	uint8_t d4 = data[3];
14
+
15
+	mpghdr->syncword		= (int)d1 << 4 | (d2 >> 4);			// 12 bits
16
+	mpghdr->ID				= bit_on(d2, bit_4);				// 1 bit
17
+	mpghdr->layer			= (d2 &~ 0xf9) >> 1;				// 2 bits
18
+	mpghdr->protection_bit	= bit_on(d2, bit_1);				// 1 bit
19
+
20
+	mpghdr->bitrate_index	= d3 >> 4;							// 4 bits
21
+	mpghdr->sampl_freq		= (d3 &~ 0xf3) >> 2;				// 2 bits
22
+	mpghdr->padding_bit		= bit_on(d3, bit_2);				// 1 bit
23
+	mpghdr->private_bit		= bit_on(d3, bit_1);				// 1 bit
24
+
25
+	mpghdr->mode			= d4 >> 6;							// 2 bits
26
+	mpghdr->mode_extension	= (d4 &~ 0xcf) >> 4;				// 2 bits
27
+	mpghdr->copyright		= bit_on(d4, bit_4);				// 1 bit
28
+	mpghdr->org_home		= bit_on(d4, bit_3);				// 1 bit
29
+	mpghdr->emphasis		= d4 &~ 0xfc;						// 2 bits
30
+
31
+	if (mpghdr->syncword != 0xfff) {
32
+		ts_LOGf("!!! Error parsing mpeg audio header! Syncword should be 0xfff but it is 0x%03x!\n", mpghdr->syncword);
33
+		return 0;
34
+	} else {
35
+		mpghdr->initialized = 1;
36
+		return 1;
37
+	}
38
+}
39
+
40
+void ts_pes_es_mpeg_audio_header_dump(struct mpeg_audio_header *mpghdr) {
41
+	if (!mpghdr->initialized)
42
+		return;
43
+	// See ISO-11172-3 for more info
44
+	ts_LOGf("  - ES analyze audio frame\n");
45
+	ts_LOGf("    - Syncword      : %x\n", mpghdr->syncword);
46
+	if (mpghdr->syncword != 0xfff) {
47
+		ts_LOGf("!!! ERROR: MPEG audo Syncword should be 0xfff!\n");
48
+		return;
49
+	}
50
+	ts_LOGf("    - ID            : %d (%s)\n", mpghdr->ID, mpghdr->ID ? "MPEG Audio" : "Other");
51
+	ts_LOGf("    - layer         : %d (%s)\n", mpghdr->layer,
52
+		mpghdr->layer == 0 ? "reserved" :
53
+		mpghdr->layer == 1 ? "Layer III" :
54
+		mpghdr->layer == 2 ? "Layer II" :
55
+		mpghdr->layer == 3 ? "Layer I" : "reserved"
56
+	);
57
+	ts_LOGf("    - protection_bit: %x\n", mpghdr->protection_bit);
58
+	int br = 0;
59
+	if (mpghdr->layer > 0 && mpghdr->layer < 4) {
60
+		int bitrate_index_table[4][16] = {
61
+			[3] = { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, -1},	// Layer 1
62
+			[2] = { 0, 32, 48, 56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320, 384, -1},	// Layer 2
63
+			[1] = { 0, 32, 40, 48,  56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320, -1}	// Layer 3
64
+		};
65
+		br = bitrate_index_table[mpghdr->layer][mpghdr->bitrate_index];
66
+	}
67
+	ts_LOGf("    - bitrate_index : %d (%d kBit/s)\n", mpghdr->bitrate_index, br);
68
+	ts_LOGf("    - sampl_freq    : %d (%s)\n", mpghdr->sampl_freq,
69
+		mpghdr->sampl_freq == 0 ? "44.1 kHz" :
70
+		mpghdr->sampl_freq == 1 ? "48 kHz" :
71
+		mpghdr->sampl_freq == 2 ? "32 kHz" : "reserved"
72
+	);
73
+	ts_LOGf("    - padding_bit   : %d\n", mpghdr->padding_bit);
74
+	ts_LOGf("    - private_bit   : %d\n", mpghdr->private_bit);
75
+	ts_LOGf("    - mode          : %d (%s)\n", mpghdr->mode,
76
+		mpghdr->mode == 0 ? "stereo" :
77
+		mpghdr->mode == 1 ? "join_stereo" :
78
+		mpghdr->mode == 2 ? "dual_channel" : "single_channel"
79
+	);
80
+	ts_LOGf("    - mode_extension: %x\n", mpghdr->mode_extension);
81
+	ts_LOGf("    - copyright     : %x\n", mpghdr->copyright);
82
+	ts_LOGf("    - org_home      : %x\n", mpghdr->org_home);
83
+	ts_LOGf("    - emphasis      : %d (%s)\n", mpghdr->emphasis,
84
+		mpghdr->emphasis == 0 ? "none" :
85
+		mpghdr->emphasis == 1 ? "50/15 microseconds" :
86
+		mpghdr->emphasis == 2 ? "reserved" : "CCITT J.17"
87
+	);
88
+}
89
+
90
+void ts_pes_es_parse(struct ts_pes *pes) {
91
+	if (!pes->es_data)
92
+		return;
93
+
94
+	// Parse MPEG audio packet header
95
+	if ((pes->is_audio_mpeg1 || pes->is_audio_mpeg2) && pes->es_data_size > 4) {
96
+		struct mpeg_audio_header mpghdr;
97
+		memset(&mpghdr, 0, sizeof(struct mpeg_audio_header));
98
+		ts_pes_es_mpeg_audio_header_parse(&mpghdr, pes->es_data, pes->es_data_size);
99
+		if (mpghdr.initialized) {
100
+			pes->mpeg_audio_header = mpghdr;
101
+			if (mpghdr.ID) {
102
+				switch (mpghdr.layer) {
103
+					case 3: pes->is_audio_mpeg1l1 = 1; break;
104
+					case 2: pes->is_audio_mpeg1l2 = 1; break;
105
+					case 1: pes->is_audio_mpeg1l3 = 1; break;
106
+				}
107
+			}
108
+		}
109
+	}
110
+
111
+	// Look into elementary streams to detect AC3/DTS
112
+	if (pes->is_audio_ac3) {
113
+		if (pes->real_pes_packet_len >= 2 && (pes->es_data[0] == 0x0B && pes->es_data[1] == 0x77)) {
114
+			pes->is_audio     = 1;
115
+			pes->is_audio_ac3 = 1;
116
+			pes->is_audio_dts = 0;
117
+		}
118
+		if (pes->real_pes_packet_len >= 4 && (pes->es_data[0] == 0x7f && pes->es_data[1] == 0xfe && pes->es_data[2] == 0x80 && pes->es_data[3] == 0x01)) {
119
+			pes->is_audio     = 1;
120
+			pes->is_audio_ac3 = 0;
121
+			pes->is_audio_dts = 1;
122
+		}
123
+	}
124
+}
125
+
126
+void ts_pes_es_dump(struct ts_pes *pes) {
127
+	if (pes->is_audio && pes->mpeg_audio_header.initialized) {
128
+		ts_pes_es_mpeg_audio_header_dump(&pes->mpeg_audio_header);
129
+	}
130
+}

+ 331
- 0
tsfuncs_pmt.c View File

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_pmt *ts_pmt_alloc() {
10
+	struct ts_pmt *pmt = calloc(1, sizeof(struct ts_pmt));
11
+	pmt->section_header	= ts_section_data_alloc();
12
+	pmt->streams_max	= 128;
13
+	pmt->streams		= calloc(pmt->streams_max, sizeof(void *));
14
+	return pmt;
15
+}
16
+
17
+void ts_pmt_free(struct ts_pmt **ppmt) {
18
+	struct ts_pmt *pmt = *ppmt;
19
+	int i;
20
+	if (pmt) {
21
+		ts_section_data_free(&pmt->section_header);
22
+		for (i=0;i<pmt->streams_num;i++) {
23
+			FREE(pmt->streams[i]->ES_info);
24
+			FREE(pmt->streams[i]);
25
+		}
26
+		FREE(pmt->program_info);
27
+		FREE(pmt->streams);
28
+		FREE(*ppmt);
29
+	}
30
+}
31
+
32
+static struct ts_pmt *ts_pmt_reset(struct ts_pmt *pmt) {
33
+	struct ts_pmt *newpmt = ts_pmt_alloc();
34
+	ts_pmt_free(&pmt);
35
+	return newpmt;
36
+}
37
+
38
+struct ts_pmt *ts_pmt_push_packet(struct ts_pmt *pmt, uint8_t *ts_packet, uint16_t pmt_pid) {
39
+	struct ts_header ts_header;
40
+	memset(&ts_header, 0, sizeof(struct ts_header));
41
+
42
+	if (ts_packet_header_parse(ts_packet, &ts_header)) {
43
+		if (ts_header.pid != pmt_pid)
44
+			goto OUT;
45
+		if (!pmt->ts_header.pusi)
46
+			pmt->ts_header = ts_header;
47
+	}
48
+
49
+	if (ts_header.pusi) {
50
+		struct ts_section_header section_header;
51
+		memset(&section_header, 0, sizeof(struct ts_section_header));
52
+
53
+		uint8_t *section_data = ts_section_header_parse(ts_packet, &pmt->ts_header, &section_header);
54
+		if (!section_data || !section_header.section_syntax_indicator) {
55
+			memset(&pmt->ts_header, 0, sizeof(struct ts_header));
56
+			goto OUT;
57
+		}
58
+		// table_id should be 0x02 (program_map_section)
59
+		if (section_header.table_id != 0x02) {
60
+			memset(&pmt->ts_header, 0, sizeof(struct ts_header));
61
+			goto OUT;
62
+		}
63
+
64
+		// Set correct section_header
65
+		ts_section_header_parse(ts_packet, &pmt->ts_header, pmt->section_header);
66
+	}
67
+
68
+	if (!pmt->initialized) {
69
+		if (pmt->section_header->section_syntax_indicator) {
70
+			ts_section_add_packet(pmt->section_header, &ts_header, ts_packet);
71
+			if (pmt->section_header->initialized) {
72
+				if (!ts_pmt_parse(pmt))
73
+					goto ERROR;
74
+			}
75
+		}
76
+	}
77
+
78
+OUT:
79
+	return pmt;
80
+
81
+ERROR:
82
+	return ts_pmt_reset(pmt);
83
+}
84
+
85
+int ts_pmt_parse(struct ts_pmt *pmt) {
86
+	uint8_t *section_data = pmt->section_header->section_data + 8; // + 8 to compensate for section table header
87
+	int section_len = pmt->section_header->packet_section_len;
88
+
89
+	pmt->reserved1         =  (section_data[0] &~ 0x1F) >> 5;						// xxx11111
90
+	pmt->PCR_pid           = ((section_data[0] &~ 0xE0) << 8) | section_data[1];	// 111xxxxx xxxxxxxx
91
+
92
+	pmt->reserved2         =  (section_data[2] &~ 0x0F) >> 4;						// xxxx1111
93
+	pmt->program_info_size = ((section_data[2] &~ 0xF0) << 8) | section_data[3];	// 1111xxxx xxxxxxxx
94
+
95
+	/* Handle streams */
96
+	uint8_t *stream_data = section_data + 4 + pmt->program_info_size;	// +4 is to compensate for reserved1,PCR,reserved2,program_info_size
97
+	int stream_len       = section_len - pmt->program_info_size - 4;		// -4 for the CRC at the end
98
+
99
+	pmt->program_info = NULL;
100
+	if (pmt->program_info_size) {
101
+		pmt->program_info = malloc(pmt->program_info_size);
102
+		if (pmt->program_info) {
103
+			memcpy(pmt->program_info, stream_data - pmt->program_info_size, pmt->program_info_size);
104
+		}
105
+	}
106
+
107
+	while (stream_len > 0) {
108
+		if (pmt->streams_num == pmt->streams_max) {
109
+			ts_LOGf("PMT contains too many streams (>%d), not all are initialized!\n", pmt->streams_max);
110
+			break;
111
+		}
112
+
113
+		struct ts_pmt_stream *sinfo = calloc(1, sizeof(struct ts_pmt_stream));
114
+
115
+		sinfo->stream_type  = stream_data[0];
116
+
117
+		sinfo->reserved1    =  (stream_data[1] &~ 0x1F) >> 5;					// xxx11111
118
+		sinfo->pid          = ((stream_data[1] &~ 0xE0) << 8) | stream_data[2];	// 111xxxxx xxxxxxxx
119
+
120
+		sinfo->reserved2    =  (stream_data[3] &~ 0x0F) >> 4;					// xxxx1111
121
+		sinfo->ES_info_size = ((stream_data[3] &~ 0xF0) << 8) | stream_data[4];	// 1111xxxx xxxxxxxx
122
+
123
+		sinfo->ES_info      = NULL;
124
+		if (sinfo->ES_info_size > 0) {
125
+			sinfo->ES_info = malloc(sinfo->ES_info_size);
126
+			memcpy(sinfo->ES_info, &stream_data[5], sinfo->ES_info_size);
127
+		}
128
+		pmt->streams[pmt->streams_num] = sinfo;
129
+		pmt->streams_num++;
130
+
131
+		stream_data += 5 + sinfo->ES_info_size;
132
+		stream_len  -= 5 + sinfo->ES_info_size;
133
+	}
134
+	pmt->CRC = (pmt->CRC << 8) | stream_data[3];
135
+	pmt->CRC = (pmt->CRC << 8) | stream_data[2];
136
+	pmt->CRC = (pmt->CRC << 8) | stream_data[1];
137
+	pmt->CRC = (pmt->CRC << 8) | stream_data[0];
138
+
139
+	u_int32_t check_crc = ts_crc32(pmt->section_header->section_data, pmt->section_header->data_size);
140
+	if (check_crc != 0) {
141
+		ts_LOGf("!!! Wrong PMT CRC! It should be 0 but it is %08x (CRC in data is 0x%08x)\n", check_crc, pmt->CRC);
142
+		return 0;
143
+	}
144
+
145
+	pmt->initialized = 1;
146
+	return 1;
147
+}
148
+
149
+void ts_pmt_generate(struct ts_pmt *pmt, uint8_t **ts_packets, int *num_packets) {
150
+	uint8_t *secdata = ts_section_data_alloc_section();
151
+	ts_section_header_generate(secdata, pmt->section_header, 0);
152
+	int curpos = 8; // Compensate for the section header, frist data byte is at offset 8
153
+
154
+	secdata[curpos + 0]  = pmt->reserved1 << 5;			// xxx11111
155
+	secdata[curpos + 0] |= pmt->PCR_pid >> 8;			// 111xxxxx xxxxxxxx
156
+	secdata[curpos + 1]  = pmt->PCR_pid &~ 0xff00;
157
+
158
+	secdata[curpos + 2]  = pmt->reserved2 << 4;			// xxxx1111
159
+	secdata[curpos + 2] |= pmt->program_info_size >> 8;	// 1111xxxx xxxxxxxx
160
+	secdata[curpos + 3]  = pmt->program_info_size &~ 0xff00;
161
+	curpos += 4; // For thje fields above
162
+
163
+	if (pmt->program_info_size) {
164
+		memcpy(secdata + curpos, pmt->program_info, pmt->program_info_size);
165
+		curpos += pmt->program_info_size;
166
+	}
167
+
168
+	int i;
169
+	for(i=0;i<pmt->streams_num;i++) {
170
+		struct ts_pmt_stream *stream = pmt->streams[i];
171
+		secdata[curpos + 0] = stream->stream_type;
172
+
173
+		secdata[curpos + 1]  = stream->reserved1 << 5;		// xxx11111
174
+		secdata[curpos + 1] |= stream->pid >> 8;			// 111xxxxx xxxxxxxx
175
+		secdata[curpos + 2]  = stream->pid &~ 0xff00;
176
+
177
+		secdata[curpos + 3]  = stream->reserved2 << 4;		// xxxx1111
178
+		secdata[curpos + 3] |= stream->ES_info_size >> 8;	// 1111xxxx xxxxxxxx
179
+		secdata[curpos + 4]  = stream->ES_info_size &~ 0xff00;
180
+		curpos += 5; // Compensate for the above
181
+
182
+		if (stream->ES_info_size > 0) {
183
+			memcpy(secdata + curpos, stream->ES_info, stream->ES_info_size);
184
+			curpos += stream->ES_info_size;
185
+		}
186
+	}
187
+    pmt->CRC = ts_section_data_calculate_crc(secdata, curpos);
188
+    curpos += 4; // CRC
189
+
190
+    ts_section_data_gen_ts_packets(&pmt->ts_header, secdata, curpos, pmt->section_header->pointer_field, ts_packets, num_packets);
191
+
192
+    FREE(secdata);
193
+}
194
+
195
+void ts_pmt_regenerate_packets(struct ts_pmt *pmt) {
196
+	uint8_t *ts_packets;
197
+	int num_packets;
198
+	ts_pmt_generate(pmt, &ts_packets, &num_packets);
199
+	FREE(pmt->section_header->packet_data);
200
+	pmt->section_header->packet_data = ts_packets;
201
+	pmt->section_header->num_packets = num_packets;
202
+}
203
+
204
+struct ts_pmt *ts_pmt_copy(struct ts_pmt *pmt) {
205
+	struct ts_pmt *newpmt = ts_pmt_alloc();
206
+	int i;
207
+	for (i=0;i<pmt->section_header->num_packets; i++) {
208
+		newpmt = ts_pmt_push_packet(newpmt, pmt->section_header->packet_data + (i * TS_PACKET_SIZE), pmt->ts_header.pid);
209
+	}
210
+	if (newpmt->initialized) {
211
+		return newpmt;
212
+	} else {
213
+		ts_LOGf("Error copying PMT!\n");
214
+		ts_pmt_free(&newpmt);
215
+		return NULL;
216
+	}
217
+}
218
+
219
+void ts_pmt_check_generator(struct ts_pmt *pmt) {
220
+	struct ts_pmt *pmt1 = ts_pmt_copy(pmt);
221
+	if (pmt1) {
222
+		ts_compare_data("PMT (tspacket->struct)",
223
+			pmt1->section_header->packet_data,
224
+			pmt->section_header->packet_data,
225
+			pmt->section_header->num_packets * TS_PACKET_SIZE);
226
+		ts_pmt_free(&pmt1);
227
+	}
228
+
229
+	uint8_t *ts_packets;
230
+	int num_packets;
231
+	ts_pmt_generate(pmt, &ts_packets, &num_packets);
232
+	if (num_packets != pmt->section_header->num_packets) {
233
+		ts_LOGf("ERROR: num_packets:%d != sec->num_packets:%d\n", num_packets, pmt->section_header->num_packets);
234
+	}
235
+	ts_compare_data("PMT (struct->tspacket)", pmt->section_header->packet_data, ts_packets, num_packets * TS_PACKET_SIZE);
236
+	free(ts_packets);
237
+}
238
+
239
+void ts_pmt_dump(struct ts_pmt *pmt) {
240
+	int i;
241
+	ts_LOGf("PMT packet\n");
242
+    for(i=0;i<pmt->section_header->num_packets;i++) {
243
+        struct ts_header tshdr;
244
+        ts_packet_header_parse(pmt->section_header->packet_data + (i * TS_PACKET_SIZE), &tshdr);
245
+        ts_packet_header_dump(&tshdr);
246
+    }
247
+    ts_section_header_dump(pmt->section_header);
248
+	ts_LOGf("  * PMT data\n");
249
+	ts_LOGf("    * PID         : %04x (%d)\n", pmt->ts_header.pid, pmt->ts_header.pid);
250
+	ts_LOGf("    * reserved1   : %d\n", pmt->reserved1);
251
+	ts_LOGf("    * PCR PID     : %04x (%d)\n", pmt->PCR_pid, pmt->PCR_pid);
252
+	ts_LOGf("    * reserved2   : %d\n", pmt->reserved2);
253
+	ts_LOGf("    * program_len : %d\n", pmt->program_info_size);
254
+	ts_LOGf("    * num_streams : %d\n", pmt->streams_num);
255
+
256
+	if (pmt->program_info_size > 0) {
257
+		ts_LOGf("  * Program info:\n");
258
+		ts_LOGf("      * program info size: %d\n", pmt->program_info_size);
259
+		ts_descriptor_dump(pmt->program_info, pmt->program_info_size);
260
+	}
261
+
262
+	for(i=0;i<pmt->streams_num;i++) {
263
+		struct ts_pmt_stream *stream = pmt->streams[i];
264
+		ts_LOGf("    * [%02d/%02d] PID %04x (%d) -> Stream type: 0x%02x (%d) /es_info_size: %d/ %s\n",
265
+			i+1, pmt->streams_num,
266
+			stream->pid, stream->pid,
267
+			stream->stream_type, stream->stream_type,
268
+			stream->ES_info_size,
269
+			h222_stream_type_desc(stream->stream_type)
270
+		);
271
+		if (stream->ES_info) {
272
+			ts_descriptor_dump(stream->ES_info, stream->ES_info_size);
273
+		}
274
+	}
275
+	ts_LOGf("  * CRC 0x%04x\n", pmt->CRC);
276
+
277
+	ts_pmt_check_generator(pmt);
278
+}
279
+
280
+/*
281
+int parse_pmt(uint8_t *ts_packet, uint16_t pmt_pid, uint16_t *pcr_pid, uint16_t *video_pid, uint16_t *audio_pid, int dump) {
282
+	struct ts_pmt *pmt = calloc(1, sizeof(struct ts_pmt));
283
+	int ret = ts_pmt_init(pmt, pmt_pid, ts_packet);
284
+	if (ret) {
285
+		int i;
286
+		*pcr_pid = pmt->PCR_pid;
287
+		for (i=0;i<pmt->streams_num;i++) {
288
+			struct ts_pmt_stream *stream = pmt->streams[i];
289
+			if (ts_is_stream_type_video(stream->stream_type))
290
+				*video_pid = stream->pid;
291
+			if (ts_is_stream_type_audio(stream->stream_type))
292
+				*audio_pid = stream->pid;
293
+		}
294
+	}
295
+	if (dump)
296
+		ts_pmt_dump(pmt);
297
+	ts_pmt_free(&pmt);
298
+	return ret;
299
+}
300
+
301
+*/
302
+
303
+int ts_pmt_is_same(struct ts_pmt *pmt1, struct ts_pmt *pmt2) {
304
+	int i;
305
+
306
+	if (pmt1->CRC == pmt2->CRC) // Same
307
+		return 1;
308
+
309
+	// If some version is not current, just claim the structures are the same
310
+	if (!pmt1->section_header->current_next_indicator || pmt2->section_header->version_number)
311
+		return 1;
312
+
313
+	if (pmt1->section_header->version_number != pmt2->section_header->version_number) // Different
314
+		return 0;
315
+
316
+	if (pmt1->PCR_pid != pmt2->PCR_pid) // Different
317
+		return 0;
318
+
319
+	if (pmt1->streams_num != pmt2->streams_num) // Different
320
+		return 0;
321
+
322
+	// Check each program and PIDs
323
+	for (i=0;i<pmt1->streams_num;i++) {
324
+		struct ts_pmt_stream *stream1 = pmt1->streams[i];
325
+		struct ts_pmt_stream *stream2 = pmt2->streams[i];
326
+		if (stream1->pid != stream2->pid) // Different
327
+			return 0;
328
+	}
329
+
330
+	return 1; // Same
331
+}

+ 235
- 0
tsfuncs_sdt.c View File

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_sdt *ts_sdt_alloc() {
10
+	struct ts_sdt *sdt = calloc(1, sizeof(struct ts_sdt));
11
+	sdt->section_header	= ts_section_data_alloc();
12
+	sdt->streams_max	= 128;
13
+	sdt->streams		= calloc(sdt->streams_max, sizeof(void *));
14
+	return sdt;
15
+}
16
+
17
+void ts_sdt_free(struct ts_sdt **psdt) {
18
+	struct ts_sdt *sdt = *psdt;
19
+	int i;
20
+	if (sdt) {
21
+		ts_section_data_free(&sdt->section_header);
22
+		for (i=0;i<sdt->streams_num;i++) {
23
+			FREE(sdt->streams[i]->descriptor_data);
24
+			FREE(sdt->streams[i]);
25
+		}
26
+		FREE(sdt->streams);
27
+		FREE(*psdt);
28
+	}
29
+}
30
+
31
+static struct ts_sdt *ts_sdt_reset(struct ts_sdt *sdt) {
32
+	struct ts_sdt *newsdt = ts_sdt_alloc();
33
+	ts_sdt_free(&sdt);
34
+	return newsdt;
35
+}
36
+
37
+struct ts_sdt *ts_sdt_push_packet(struct ts_sdt *sdt, uint8_t *ts_packet) {
38
+	struct ts_header ts_header;
39
+	memset(&ts_header, 0, sizeof(struct ts_header));
40
+
41
+	if (ts_packet_header_parse(ts_packet, &ts_header)) {
42
+		// SDT should be with PID 0x11
43
+		if (ts_header.pid != 0x11)
44
+			goto OUT;
45
+		if (!sdt->ts_header.pusi)
46
+			sdt->ts_header = ts_header;
47
+	}
48
+
49
+	if (ts_header.pusi) {
50
+		struct ts_section_header section_header;
51
+		memset(&section_header, 0, sizeof(struct ts_section_header));
52
+
53
+		uint8_t *section_data = ts_section_header_parse(ts_packet, &sdt->ts_header, &section_header);
54
+		if (!section_data || !section_header.section_syntax_indicator) {
55
+			memset(&sdt->ts_header, 0, sizeof(struct ts_header));
56
+			goto OUT;
57
+		}
58
+		// table_id should be 0x42 (service_description_section - actual_transport_stream)
59
+		if (section_header.table_id != 0x42) {
60
+			memset(&sdt->ts_header, 0, sizeof(struct ts_header));
61
+			goto OUT;
62
+		}
63
+
64
+		// Set correct section_header
65
+		ts_section_header_parse(ts_packet, &sdt->ts_header, sdt->section_header);
66
+	}
67
+
68
+	if (!sdt->initialized) {
69
+		if (sdt->section_header->section_syntax_indicator) {
70
+			ts_section_add_packet(sdt->section_header, &ts_header, ts_packet);
71
+			if (sdt->section_header->initialized) {
72
+				if (!ts_sdt_parse(sdt))
73
+					goto ERROR;
74
+			}
75
+		}
76
+	}
77
+
78
+OUT:
79
+	return sdt;
80
+
81
+ERROR:
82
+	return ts_sdt_reset(sdt);
83
+}
84
+
85
+int ts_sdt_parse(struct ts_sdt *sdt) {
86
+	uint8_t *section_data = sdt->section_header->section_data + 8; // + 8 to compensate for section table header
87
+	int section_len = sdt->section_header->packet_section_len;
88
+
89
+	// 3 bytes
90
+	sdt->original_network_id = (section_data[0] << 8) | section_data[1];
91
+	sdt->reserved            = section_data[2];
92
+
93
+	section_data = section_data + 3;
94
+	section_len  = section_len -3;
95
+
96
+	while (section_len > 0) {
97
+		if (sdt->streams_num == sdt->streams_max) {
98
+			ts_LOGf("SDT contains too many streams (>%d), not all are initialized!\n", sdt->streams_max);
99
+			break;
100
+		}
101
+
102
+		struct ts_sdt_stream *sinfo = calloc(1, sizeof(struct ts_sdt_stream));
103
+
104
+		sinfo->service_id = (section_data[0] << 8) | section_data[1];
105
+
106
+		sinfo->reserved1                  =  (section_data[2] &~ 0x03) >> 2;	// xxxxxx11
107
+		sinfo->EIT_schedule_flag          =  (section_data[2] &~ 0xFD) >> 1;	// 111111x1
108
+		sinfo->EIT_present_following_flag =  (section_data[2] &~ 0xFE);		// 1111111x
109
+
110
+		sinfo->running_status  = section_data[3] >> 5;						// 111xxxxx
111
+		sinfo->free_CA_mode    = (section_data[3] &~ 0xE0) >> 4;				// xxx1xxxx
112
+		sinfo->descriptor_size = ((section_data[3] &~ 0xF0) << 8) | section_data[4];	// 1111xxxx xxxxxxxx
113
+
114
+		sinfo->descriptor_data      = NULL;
115
+		if (sinfo->descriptor_size > 0) {
116
+			sinfo->descriptor_data = malloc(sinfo->descriptor_size);
117
+			memcpy(sinfo->descriptor_data, &section_data[5], sinfo->descriptor_size);
118
+		}
119
+		sdt->streams[sdt->streams_num] = sinfo;
120
+		sdt->streams_num++;
121
+
122
+		section_data += 5 + sinfo->descriptor_size;
123
+		section_len  -= 5 + sinfo->descriptor_size;
124
+	}
125
+	sdt->CRC = (sdt->CRC << 8) | section_data[3];
126
+	sdt->CRC = (sdt->CRC << 8) | section_data[2];
127
+	sdt->CRC = (sdt->CRC << 8) | section_data[1];
128
+	sdt->CRC = (sdt->CRC << 8) | section_data[0];
129
+
130
+	u_int32_t check_crc = ts_crc32(sdt->section_header->section_data, sdt->section_header->data_size);
131
+	if (check_crc != 0) {
132
+		ts_LOGf("!!! Wrong SDT CRC! It should be 0 but it is %08x (CRC in data is 0x%08x)\n", check_crc, sdt->CRC);
133
+		return 0;
134
+	}
135
+
136
+	sdt->initialized = 1;
137
+	return 1;
138
+}
139
+
140
+void ts_sdt_generate(struct ts_sdt *sdt, uint8_t **ts_packets, int *num_packets) {
141
+	uint8_t *secdata = ts_section_data_alloc_section();
142
+	ts_section_header_generate(secdata, sdt->section_header, 0);
143
+	int curpos = 8; // Compensate for the section header, frist data byte is at offset 8
144
+
145
+	secdata[curpos + 0] = sdt->original_network_id >> 8;	// 1111xxxx xxxxxxxx
146
+	secdata[curpos + 1] = sdt->original_network_id &~ 0xff00;
147
+	secdata[curpos + 2] = sdt->reserved;
148
+	curpos += 3; // For the fields above
149
+
150
+	int i;
151
+	for(i=0;i<sdt->streams_num;i++) {
152
+		struct ts_sdt_stream *stream = sdt->streams[i];
153
+
154
+		secdata[curpos + 0]  = stream->service_id >> 8;			// xxxxxxxx xxxxxxxx
155
+		secdata[curpos + 1]  = stream->service_id &~ 0xff00;
156
+
157
+		secdata[curpos + 2]  = stream->reserved1 << 2;				// xxxxxx11
158
+		secdata[curpos + 2] |= stream->EIT_schedule_flag << 1;		// 111111x1
159
+		secdata[curpos + 2] |= stream->EIT_present_following_flag;	// 1111111x
160
+
161
+		secdata[curpos + 3]  = stream->running_status << 5;		// 111xxxxx
162
+		secdata[curpos + 3] |= stream->free_CA_mode   << 4;		// xxx1xxxx
163
+		secdata[curpos + 3] |= stream->descriptor_size >> 8;		// 1111xxxx xxxxxxxx
164
+		secdata[curpos + 4]  = stream->descriptor_size &~ 0xff00;
165
+		curpos += 5; // Compensate for the above
166
+
167
+		if (stream->descriptor_size > 0) {
168
+			memcpy(secdata + curpos, stream->descriptor_data, stream->descriptor_size);
169
+			curpos += stream->descriptor_size;
170
+		}
171
+	}
172
+    sdt->CRC = ts_section_data_calculate_crc(secdata, curpos);
173
+    curpos += 4; // CRC
174
+
175
+    ts_section_data_gen_ts_packets(&sdt->ts_header, secdata, curpos, sdt->section_header->pointer_field, ts_packets, num_packets);
176
+
177
+    FREE(secdata);
178
+}
179
+
180
+void ts_sdt_check_generator(struct ts_sdt *sdt) {
181
+	struct ts_sdt *sdt1 = ts_sdt_alloc();
182
+	int i;
183
+	for (i=0;i<sdt->section_header->num_packets;i++) {
184
+		sdt1 = ts_sdt_push_packet(sdt1, sdt->section_header->packet_data + (i * TS_PACKET_SIZE));
185
+	}
186
+	ts_compare_data("SDT (tspacket->struct)",
187
+		sdt1->section_header->packet_data,
188
+		sdt->section_header->packet_data,
189
+		sdt->section_header->num_packets * TS_PACKET_SIZE);
190
+	ts_sdt_free(&sdt1);
191
+
192
+	uint8_t *ts_packets;
193
+	int num_packets;
194
+	ts_sdt_generate(sdt, &ts_packets, &num_packets);
195
+	if (num_packets != sdt->section_header->num_packets) {
196
+		ts_LOGf("ERROR: num_packets:%d != sec->num_packets:%d\n", num_packets, sdt->section_header->num_packets);
197
+	}
198
+	ts_compare_data("SDT (struct->tspacket)", sdt->section_header->packet_data, ts_packets, num_packets * TS_PACKET_SIZE);
199
+	free(ts_packets);
200
+}
201
+
202
+void ts_sdt_dump(struct ts_sdt *sdt) {
203
+	int i;
204
+	ts_LOGf("SDT packet\n");
205
+    for(i=0;i<sdt->section_header->num_packets;i++) {
206
+        struct ts_header tshdr;
207
+        ts_packet_header_parse(sdt->section_header->packet_data + (i * TS_PACKET_SIZE), &tshdr);
208
+        ts_packet_header_dump(&tshdr);
209
+    }
210
+    ts_section_header_dump(sdt->section_header);
211
+	ts_LOGf("  * SDT data\n");
212
+	ts_LOGf("    * PID         : %04x (%d)\n", sdt->ts_header.pid, sdt->ts_header.pid);
213
+	ts_LOGf("    * org_net_id  : %04x (%d)\n", sdt->original_network_id, sdt->original_network_id);
214
+	ts_LOGf("    * reserved    : %d\n", sdt->reserved);
215
+	ts_LOGf("    * num_streams : %d\n", sdt->streams_num);
216
+
217
+	for(i=0;i<sdt->streams_num;i++) {
218
+		struct ts_sdt_stream *stream = sdt->streams[i];
219
+		ts_LOGf("    * [%02d/%02d] Service_id: %04x (%d) Res1: %d EIT_schedule: %d EIT_present: %d Running_status: %d free_CA_mode: %d /es_info_size: %d/\n",
220
+			i+1, sdt->streams_num,
221
+			stream->service_id, stream->service_id,
222
+			stream->reserved1,
223
+			stream->EIT_schedule_flag,
224
+			stream->EIT_present_following_flag,
225
+			stream->running_status,
226
+			stream->free_CA_mode,
227
+			stream->descriptor_size);
228
+		if (stream->descriptor_data) {
229
+			ts_descriptor_dump(stream->descriptor_data, stream->descriptor_size);
230
+		}
231
+	}
232
+	ts_LOGf("  * CRC 0x%04x\n", sdt->CRC);
233
+
234
+	ts_sdt_check_generator(sdt);
235
+}

+ 128
- 0
tsfuncs_sdt_desc.c View File

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_sdt_regenerate_packet_data(struct ts_sdt *sdt) {
10
+	uint8_t *ts_packets;
11
+	int num_packets;
12
+	ts_sdt_generate(sdt, &ts_packets, &num_packets);
13
+	memcpy(sdt->section_header->packet_data, ts_packets, num_packets * TS_PACKET_SIZE);
14
+	sdt->section_header->num_packets = num_packets;
15
+	free(ts_packets);
16
+}
17
+
18
+static void ts_sdt_init_private_variables(struct ts_sdt *sdt) {
19
+	sdt->section_header->data_size          = sdt->section_header->section_length + 3;
20
+	sdt->section_header->packet_section_len = sdt->section_header->data_size - 8 - 4;	// -8 for the section header, -4 for the CRC at the end
21
+	ts_sdt_regenerate_packet_data(sdt);
22
+}
23
+
24
+struct ts_sdt *ts_sdt_alloc_init(uint16_t org_network_id, uint16_t transport_stream_id) {
25
+	struct ts_sdt *sdt = ts_sdt_alloc();
26
+
27
+	sdt->ts_header.pid            = 0x11;
28
+	sdt->ts_header.pusi           = 1;
29
+	sdt->ts_header.payload_field  = 1;
30
+	sdt->ts_header.payload_offset = 4;
31
+
32
+	sdt->section_header->table_id                 = 0x42;
33
+	sdt->section_header->version_number           = 1;
34
+	sdt->section_header->current_next_indicator   = 1;
35
+	sdt->section_header->section_syntax_indicator = 1;
36
+	sdt->section_header->private_indicator        = 1;
37
+	sdt->section_header->section_length           = 9 + 3; // Empty section (9) + 3 (16+8) for SDT table data
38
+	sdt->section_header->ts_id_number             = transport_stream_id;
39
+	sdt->section_header->reserved1                = 3;
40
+	sdt->section_header->reserved2                = 3;
41
+
42
+	sdt->original_network_id = org_network_id;	// 16 bits
43
+	sdt->reserved            = 0xff;			// 8 bits
44
+
45
+	sdt->initialized = 1;
46
+
47
+	ts_sdt_init_private_variables(sdt);
48
+
49
+	return sdt;
50
+}
51
+
52
+static int ts_sdt_add_stream(struct ts_sdt *sdt, uint16_t service_id, uint8_t *desc, uint8_t desc_size) {
53
+	if (sdt->streams_num == sdt->streams_max - 1 || desc_size == 0) {
54
+		FREE(desc);
55
+		return 0;
56
+	}
57
+
58
+	int stream_len = 2 + 1 + 2 + desc_size;
59
+	if (stream_len + sdt->section_header->section_length > 4093) {
60
+		ts_LOGf("SDT no space left, max 4093, current %d will become %d!\n",
61
+			sdt->section_header->section_length,
62
+			stream_len + sdt->section_header->section_length);
63
+		free(desc);
64
+		return 0;
65
+	}
66
+
67
+	sdt->section_header->section_length += stream_len;
68
+
69
+	struct ts_sdt_stream *sinfo = calloc(1, sizeof(struct ts_sdt_stream));
70
+	sinfo->service_id                 = service_id;	// 16 bits (2 bytes)
71
+	sinfo->reserved1                  = 63;			// 6 bits are up
72
+	sinfo->EIT_schedule_flag          = 0;			// 1 bit
73
+	sinfo->EIT_present_following_flag = 1;			// 1 bit (1 byte) We have EIT
74
+	sinfo->running_status             = 4;			// 3 bits
75
+	sinfo->free_CA_mode               = 1;			// 1 bit
76
+
77
+	sinfo->descriptor_size            = desc_size;	// 12 bits (2 bytes)
78
+	sinfo->descriptor_data            = desc;		// desc_size bytes
79
+
80
+	sdt->streams[sdt->streams_num] = sinfo;
81
+	sdt->streams_num++;
82
+
83
+	ts_sdt_init_private_variables(sdt);
84
+
85
+	return 1;
86
+}
87
+
88
+int ts_sdt_add_service_descriptor(struct ts_sdt *sdt, uint16_t service_id, uint8_t video, char *provider_name, char *service_name) {
89
+	char *name;
90
+	if (!service_name && !provider_name)
91
+		return 0;
92
+	int desc_size = 2 + 1; // 2 tag, size; 1 service_type
93
+	desc_size += 1 + (provider_name ? strlen(provider_name) : 0);
94
+	desc_size += 1 + (service_name  ? strlen(service_name)  : 0);
95
+	if (desc_size > 257) {
96
+		ts_LOGf("SDT service_descriptor size > 255 is not supported (%d)!\n", desc_size);
97
+		return 0;
98
+	}
99
+
100
+	int dpos = 0;
101
+	uint8_t *desc = calloc(1, desc_size);
102
+	desc[dpos + 0] = 0x48;					// Service descriptor
103
+	desc[dpos + 1] = desc_size - 2;			// -2 Because of two byte header
104
+	desc[dpos + 2] = video ? 0x01 : 0x02;	// DVB Table 75: Service type coding: 0x01 - digital tv, 0x02 - digital radio
105
+	desc[dpos + 3] = (provider_name ? strlen(provider_name) : 0);
106
+	dpos += 4;
107
+	if (!provider_name || strlen(provider_name) == 0) {
108
+		dpos++;
109
+	} else {
110
+		name = provider_name;
111
+		while (name[0]) {
112
+			desc[dpos++] = name[0];
113
+			name++;
114
+		}
115
+	}
116
+	if (!service_name || strlen(service_name) == 0) {
117
+		dpos++;
118
+	} else {
119
+		desc[dpos++] = (service_name  ? strlen(service_name)  : 0);
120
+		name = service_name;
121
+		while (name[0]) {
122
+			desc[dpos++] = name[0];
123
+			name++;
124
+		}
125
+	}
126
+
127
+	return ts_sdt_add_stream(sdt, service_id, desc, desc_size);
128
+}

+ 18
- 0
tsfuncs_sdt_test.c View File

1
+int ts_sdt_test() {
2
+	struct ts_sdt *sdt = ts_sdt_alloc_init(1, 2);
3
+
4
+	ts_sdt_add_service_descriptor(sdt, 1007, 1, "BULSATCOM", "bTV");
5
+	ts_sdt_dump(sdt);
6
+
7
+	int i;
8
+	for (i=0;i<120;i++) {
9
+		ts_sdt_add_service_descriptor(sdt, 9,  0, "PROVIDER", "SERVICE33333333333333333333333333333333333333333333333333333333333333");
10
+		ts_sdt_add_service_descriptor(sdt, 13, 0, "PROddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddVIDER", "SERVICE");
11
+		ts_sdt_add_service_descriptor(sdt, 7,  0, "PROVIDER", "SERVICE");
12
+	}
13
+	ts_sdt_dump(sdt);
14
+
15
+	write(1, sdt->section_header->packet_data, sdt->section_header->num_packets * 188);
16
+	ts_sdt_free(sdt);
17
+	return 0;
18
+}

+ 118
- 0
tsfuncs_section_data.c View File

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
+
11
+uint8_t *ts_section_data_alloc_section() {
12
+	uint8_t *data = malloc(4096);
13
+	memset(data, 0x30, 4096);
14
+	return data;
15
+}
16
+
17
+uint8_t *ts_section_data_alloc_packet() {
18
+	uint8_t *data = malloc(5120);
19
+	memset(data, 0x31, 5120);
20
+	return data;
21
+}
22
+
23
+struct ts_section_header *ts_section_data_alloc() {
24
+	struct ts_section_header *section_data = calloc(1, sizeof(struct ts_section_header));
25
+	section_data->section_data = ts_section_data_alloc_section();
26
+	section_data->packet_data  = ts_section_data_alloc_packet();
27
+	return section_data;
28
+}
29
+
30
+void ts_section_data_free(struct ts_section_header **psection_data) {
31
+	struct ts_section_header *section_data = *psection_data;
32
+	if (section_data) {
33
+		FREE(section_data->section_data);
34
+		FREE(section_data->packet_data);
35
+		FREE(*psection_data);
36
+	}
37
+}
38
+
39
+// Fill CRC of the section data after secdata_size bytes
40
+uint32_t ts_section_data_calculate_crc(uint8_t *section_data, int secdata_size) {
41
+	uint32_t check_crc = ts_crc32(section_data, secdata_size);
42
+	section_data[secdata_size + 0] = ((check_crc &~ 0x00ffffff) >> 24);
43
+	section_data[secdata_size + 1] = ((check_crc &~ 0xff00ffff) >> 16);
44
+	section_data[secdata_size + 2] = ((check_crc &~ 0xffff00ff) >>  8);
45
+	section_data[secdata_size + 3] =  (check_crc &~ 0xffffff00);
46
+	return check_crc;
47
+}
48
+
49
+#define min(a,b) ((a < b) ? a : b)
50
+
51
+// Returns alllocated and build ts packets in *packets "ts_header"
52
+// Returns number of packets in *num_packets
53
+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) {
54
+	struct ts_header tshdr = *ts_header;
55
+	*packets = ts_section_data_alloc_packet();
56
+	int np = 1; // Minimum 1 TS packet
57
+	int section_sz = section_data_sz; // Add 4 bytes CRC!
58
+	int sect = section_sz - (TS_PACKET_SIZE - 5);
59
+	while (sect > 0) {
60
+		sect -= TS_PACKET_SIZE - 4;
61
+		np++;
62
+	}
63
+	int i, sect_pos = 0, sect_dataleft = section_sz;
64
+	*num_packets = np;
65
+	int dataofs;
66
+	for (i=0;i<np;i++) {
67
+		uint8_t *curpacket = *packets + (i * TS_PACKET_SIZE);	// Start of the current packet
68
+
69
+		dataofs = 4; // Start after the TS header
70
+		if (i == 0) { // First packet have pointer field
71
+			if (ts_header->adapt_len)
72
+				dataofs += ts_header->adapt_len + 1; // +1 for flags
73
+			dataofs += pointer_field + 1;
74
+		} else { // For the following packets after the first correct flags
75
+			tshdr.pusi = 0;
76
+			tshdr.continuity++;
77
+		}
78
+		ts_packet_header_generate(curpacket, &tshdr);				// Do the header
79
+		if (i == 0) { // Set pointer field in the first packet
80
+			if (ts_header->adapt_len) {
81
+				curpacket[4] = ts_header->adapt_len;
82
+				curpacket[5] = 0;	// Adaptation field flags, all off
83
+				curpacket[5 + ts_header->adapt_len] = pointer_field;
84
+			} else { // No adaptation field, just set pointer field
85
+				curpacket[4] = pointer_field;
86
+			}
87
+		}
88
+
89
+		uint8_t maxdatasize = TS_PACKET_SIZE - dataofs;		// How much data can this packet carry
90
+		int copied = min(maxdatasize, sect_dataleft);
91
+		memcpy(curpacket + dataofs, section_data + sect_pos, copied);	// Fill the data
92
+		sect_pos      += maxdatasize;
93
+		sect_dataleft -= maxdatasize;
94
+		if (sect_dataleft < 0)
95
+			break;
96
+	}
97
+}
98
+
99
+void ts_section_add_packet(struct ts_section_header *sec, struct ts_header *ts_header, uint8_t *ts_packet) {
100
+	uint8_t payload_offset = ts_header->payload_offset;
101
+	if (ts_header->pusi) {
102
+		payload_offset += sec->pointer_field + 1; // Pointer field
103
+	}
104
+
105
+	int to_copy = TS_PACKET_SIZE - payload_offset;
106
+	if (to_copy <= 0)
107
+		return;
108
+
109
+	if (sec->section_pos + to_copy >= 4092) {
110
+		to_copy = (sec->section_length + 4) - sec->section_pos;
111
+	}
112
+
113
+	memcpy(sec->section_data + sec->section_pos, ts_packet + payload_offset, to_copy);
114
+	memcpy(sec->packet_data + (sec->num_packets * TS_PACKET_SIZE), ts_packet, TS_PACKET_SIZE);
115
+	sec->section_pos += to_copy;
116
+	sec->num_packets++;
117
+	sec->initialized = (sec->section_pos+1) >= (sec->section_length + 4); // +4 to include the CRC
118
+}

+ 134
- 0
tsfuncs_sections.c View File

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
+uint8_t *ts_section_header_parse(uint8_t *ts_packet, struct ts_header *ts_header, struct ts_section_header *ts_section_header) {
11
+	if (ts_header->payload_offset + 8 > TS_PACKET_SIZE) {
12
+		ts_packet_header_dump(ts_header);
13
+		ts_LOGf("!!! Section start outside of TS packet %d!\n", ts_header->payload_offset + 8);
14
+		return NULL;
15
+	}
16
+
17
+	uint8_t *data = ts_packet + ts_header->payload_offset;
18
+
19
+	ts_section_header->pointer_field = data[0];
20
+	data += ts_section_header->pointer_field + 1;
21
+
22
+	ts_section_header->table_id                 = data[0];
23
+
24
+	ts_section_header->section_syntax_indicator = data[1] >> 7;				// x1111111
25
+	ts_section_header->private_indicator        = (data[1] &~ 0xBF) >> 6;	// 1x111111
26
+	ts_section_header->reserved1                = (data[1] &~ 0xCF) >> 4;	// 11xx1111
27
+	ts_section_header->section_length           = ((data[1] &~ 0xF0) << 8) | data[2]; // 1111xxxx xxxxxxxx
28
+
29
+	if (ts_section_header->section_length == 0)
30
+		return NULL;
31
+
32
+	// Stuffing table, ignore.
33
+	if (ts_section_header->table_id == 0x72)
34
+		return NULL;
35
+
36
+	ts_section_header->ts_id_number             = (data[3] << 8) | data[4]; // xxxxxxx xxxxxxx
37
+
38
+	ts_section_header->reserved2                = data[5] >> 6;				// xx111111
39
+	ts_section_header->version_number           = (data[5] &~ 0xC1) >> 1;	// 11xxxxx1
40
+	ts_section_header->current_next_indicator   = data[5] &~ 0xFE;			// 1111111x
41
+
42
+	ts_section_header->section_number           = data[6];
43
+	ts_section_header->last_section_number      = data[7];
44
+
45
+	if (!ts_section_header->section_syntax_indicator) {
46
+		ts_LOGf("!!! Table 0x%02x have no section_syntax_indicator set!\n",
47
+			ts_section_header->table_id);
48
+		ts_packet_header_dump(ts_header);
49
+		ts_section_header_dump(ts_section_header);
50
+		return NULL;
51
+	}
52
+
53
+	ts_section_header->data_size = ts_section_header->section_length + 3;
54
+	ts_section_header->packet_section_len = ts_section_header->data_size - 8 - 4;	// -8 for the section header, -4 for the CRC at the end
55
+
56
+	return data + 8;
57
+}
58
+
59
+void ts_section_header_generate(uint8_t *ts_packet, struct ts_section_header *ts_section_header, uint8_t start) {
60
+	ts_packet[start + 0] = ts_section_header->table_id;
61
+
62
+	ts_packet[start + 1]  = ts_section_header->section_syntax_indicator << 7;		// x1111111
63
+	ts_packet[start + 1] |= ts_section_header->private_indicator        << 6;		// 1x111111
64
+	ts_packet[start + 1] |= ts_section_header->reserved1                << 4;		// 11xx1111
65
+	ts_packet[start + 1] |= ts_section_header->section_length           >> 8;		// 1111xxxx xxxxxxxx
66
+	ts_packet[start + 2]  = ts_section_header->section_length           &~ 0xff00;	// 1111xxxx xxxxxxxx
67
+
68
+	ts_packet[start + 3]  = ts_section_header->ts_id_number             >> 8;		// xxxxxxxx xxxxxxxx
69
+	ts_packet[start + 4]  = ts_section_header->ts_id_number             &~ 0xff00;
70
+
71
+	ts_packet[start + 5]  = ts_section_header->reserved2                 << 6;		// xx111111
72
+	ts_packet[start + 5] |= ts_section_header->version_number            << 1;		// 11xxxxx1
73
+	ts_packet[start + 5] |= ts_section_header->current_next_indicator;				// 1111111x
74
+
75
+	ts_packet[start + 6] = ts_section_header->section_number;
76
+	ts_packet[start + 7] = ts_section_header->last_section_number;
77
+}
78
+
79
+#define IN(x, a, b) \
80
+	(x >= a && x <= b)
81
+
82
+void ts_section_header_dump(struct ts_section_header *t) {
83
+	ts_LOGf("%s", "  * Section header\n");
84
+	if (t->pointer_field)
85
+	ts_LOGf("    - Pointer field      : %d\n", t->pointer_field);
86
+	ts_LOGf("    - Table id           : %03x (%d) %s\n", t->table_id, t->table_id,
87
+		t->table_id == 0x00         ? "program_association_section" :
88
+		t->table_id == 0x01         ? "conditional_access_section" :
89
+		t->table_id == 0x02         ? "program_map_section" :
90
+		t->table_id == 0x03         ? "transport_stream_description_section" :
91
+		IN(t->table_id, 0x04, 0x3f) ? "reserved" :
92
+		t->table_id == 0x40         ? "network_information_section - actual_network" :
93
+		t->table_id == 0x41         ? "network_information_section - other_network" :
94
+		t->table_id == 0x42         ? "service_description_section - actual_transport_stream" :
95
+		IN(t->table_id, 0x43, 0x45) ? "reserved for future use" :
96
+		t->table_id == 0x46         ? "service_description_section - other_transport_stream" :
97
+		IN(t->table_id, 0x47, 0x49) ? "reserved for future use" :
98
+		t->table_id == 0x4a         ? "bouquet_association_section" :
99
+		IN(t->table_id, 0x4b, 0x4d) ? "reserved for future use" :
100
+		t->table_id == 0x4e         ? "event_information_section - actual_transport_stream, present/following" :
101
+		t->table_id == 0x4f         ? "event_information_section - other_transport_stream, present/following" :
102
+		IN(t->table_id, 0x50, 0x5f) ? "event_information_section - actual_transport_stream, schedule" :
103
+		IN(t->table_id, 0x60, 0x6f) ? "event_information_section - other_transport_stream, schedule" :
104
+		t->table_id == 0x70         ? "time_date_section" :
105
+		t->table_id == 0x71         ? "running_status_section" :
106
+		t->table_id == 0x72         ? "stuffing_section" :
107
+		t->table_id == 0x73         ? "time_offset_section" :
108
+		t->table_id == 0x74         ? "application information section (TS 102 812 [15])" :
109
+		t->table_id == 0x75         ? "container section (TS 102 323 [13])" :
110
+		t->table_id == 0x76         ? "related content section (TS 102 323 [13])" :
111
+		t->table_id == 0x77         ? "content identifier section (TS 102 323 [13])" :
112
+		t->table_id == 0x78         ? "MPE-FEC section (EN 301 192 [4])" :
113
+		t->table_id == 0x79         ? "resolution notification section (TS 102 323 [13])" :
114
+		IN(t->table_id, 0x79, 0x7d) ? "reserved for future use" :
115
+		t->table_id == 0x7e         ? "discontinuity_information_section" :
116
+		t->table_id == 0x7f         ? "section_information_section" :
117
+		IN(t->table_id, 0x80, 0xfe) ? "user defined" :
118
+		t->table_id == 0xff         ? "reserved" : "Impossible!"
119
+	);
120
+	ts_LOGf("    - Section length     : %03x (%d)\n", t->section_length, t->section_length);
121
+	ts_LOGf("    - TS ID / Program No : %04x (%d)\n", t->ts_id_number, t->ts_id_number);
122
+	ts_LOGf("    - Version number %d, current next %d, section number %d, last section number %d\n",
123
+			t->version_number,
124
+			t->current_next_indicator,
125
+			t->section_number,
126
+			t->last_section_number);
127
+	ts_LOGf("    - Private vars       : data_size:%d packet_section_len:%d num_packets:%d section_pos:%d\n",
128
+			t->data_size,
129
+			t->packet_section_len,
130
+			t->num_packets,
131
+			t->section_pos);
132
+}
133
+
134
+#undef IN

+ 324
- 0
tsfuncs_tdt.c View File

1
+#include <stdio.h>
2
+#include <unistd.h>
3
+#include <netdb.h>
4
+#include <stdlib.h>
5
+#include <string.h>
6
+#include <time.h>
7
+
8
+#include "tsfuncs.h"
9
+
10
+struct ts_tdt *ts_tdt_alloc() {
11
+	struct ts_tdt *tdt = calloc(1, sizeof(struct ts_tdt));
12
+	tdt->packet_data = malloc(TS_PACKET_SIZE);
13
+	memset(tdt->packet_data, 0x32, TS_PACKET_SIZE);
14
+	return tdt;
15
+}
16
+
17
+void ts_tdt_free(struct ts_tdt **ptdt) {
18
+	struct ts_tdt *tdt = *ptdt;
19
+	if (tdt) {
20
+		FREE(tdt->packet_data);
21
+		FREE(tdt->descriptors);
22
+		FREE(*ptdt);
23
+	}
24
+}
25
+
26
+static void ts_tdt_init_empty(struct ts_tdt *tdt, time_t ts, int tot) {
27
+	tdt->ts_header.pid            = 0x14;
28
+	tdt->ts_header.pusi           = 1;
29
+	tdt->ts_header.payload_field  = 1;
30
+	tdt->ts_header.payload_offset = 4;
31
+	tdt->ts_header.continuity     = 7;
32
+
33
+	tdt->table_id                 = 0x70;
34
+	tdt->section_syntax_indicator = 0;
35
+	tdt->reserved_1               = 1;
36
+	tdt->reserved_2               = 3;
37
+	tdt->section_length           = 5;
38
+
39
+	ts_time_encode_mjd(&tdt->mjd, &tdt->bcd, &ts, NULL);
40
+	tdt->utc = ts_time_decode_mjd(tdt->mjd, tdt->bcd, &tdt->tm);
41
+
42
+	if (tot) {
43
+		tdt->table_id            = 0x73;
44
+		tdt->reserved_3          = 0xf;
45
+		tdt->descriptors_size    = 0;
46
+		tdt->CRC                 = 0;
47
+		tdt->section_length     += 2 + 4;	// 2 bytes reserved+descripts_size
48
+	}
49
+
50
+	ts_tdt_generate(tdt, tdt->packet_data);
51
+
52
+	tdt->initialized = 1;
53
+}
54
+
55
+struct ts_tdt *ts_tdt_alloc_init(time_t ts) {
56
+	struct ts_tdt *tdt = ts_tdt_alloc();
57
+	ts_tdt_init_empty(tdt, ts, 0);
58
+	return tdt;
59
+}
60
+
61
+struct ts_tdt *ts_tot_alloc_init(time_t ts) {
62
+	struct ts_tdt *tdt = ts_tdt_alloc();
63
+	ts_tdt_init_empty(tdt, ts, 1);
64
+	return tdt;
65
+}
66
+
67
+static void ts_tdt_check_generator(struct ts_tdt *tdt) {
68
+	struct ts_tdt *tdt1 = ts_tdt_alloc();
69
+	ts_tdt_parse(tdt1, tdt->packet_data);
70
+	ts_compare_data("TDT/TOT (packet->data)", tdt1->packet_data, tdt->packet_data, TS_PACKET_SIZE);
71
+	ts_tdt_free(&tdt1);
72
+
73
+	uint8_t *tmp = malloc(TS_PACKET_SIZE);
74
+	ts_tdt_generate(tdt, tmp);
75
+	ts_compare_data("TDT/TOT (data->packet)", tdt->packet_data, tmp, TS_PACKET_SIZE);
76
+	free(tmp);
77
+}
78
+
79
+int ts_tdt_parse(struct ts_tdt *tdt, uint8_t *ts_packet) {
80
+	uint8_t *data = ts_packet_header_parse(ts_packet, &tdt->ts_header);
81
+
82
+	if (!data)
83
+		return 0;
84
+
85
+	if (tdt->ts_header.pid != 0x14) // TOT/TDT
86
+		return 0;
87
+
88
+	tdt->pointer_field = data[0];
89
+	data += tdt->pointer_field + 1;
90
+
91
+	if ((data + 8) - ts_packet > TS_PACKET_SIZE) {
92
+		ts_LOGf("!!! Section start outside of TS packet!\n");
93
+		return 0;
94
+	}
95
+
96
+	if (data[0] != 0x70 && data[0] != 0x73) { // TDT or TOT
97
+		ts_LOGf("Invalid TDT/TOT Table_ID 0x%02x\n", data[0]);
98
+		return 0;
99
+	}
100
+
101
+	tdt->table_id                 = data[0];
102
+	tdt->section_syntax_indicator = data[1] >> 7;			// x1111111
103
+	tdt->reserved_1               = (data[1] &~ 0xBF) >> 6;	// 1x111111
104
+	tdt->reserved_2               = (data[1] &~ 0xCF) >> 4;	// 11xx1111
105
+	tdt->section_length           = ((data[1] &~ 0xF0) << 8) | data[2]; // 1111xxxx xxxxxxxx
106
+	if (tdt->section_length > TS_MAX_PAYLOAD_SIZE - 8) {
107
+		ts_LOGf("TDT/TOT section length is too big: %d (max: %d)\n", tdt->section_length, TS_MAX_PAYLOAD_SIZE - 8);
108
+		return 0;
109
+	}
110
+
111
+	tdt->mjd       = (data[3] << 8) | data[4];
112
+	tdt->bcd       = ((data[5] << 16) | (data[6] << 8)) | data[7];
113
+
114
+	if (tdt->table_id == 0x73) { // TOT
115
+		tdt->reserved_3        = data[8] >> 4;		// xxxx1111
116
+		tdt->descriptors_size  = data[8] &~ 0xf0;	// 1111xxxx
117
+		tdt->descriptors_size |= data[9];			// xxxxxxxx
118
+		if (tdt->descriptors_size > TS_MAX_PAYLOAD_SIZE - 10) {
119
+			ts_LOGf("TDT/TOT descriptors_size is too big: %d (max: %d)\n", tdt->descriptors_size, TS_MAX_PAYLOAD_SIZE - 10);
120
+			return 0;
121
+		}
122
+		if (tdt->descriptors_size) {
123
+			tdt->descriptors = malloc(tdt->descriptors_size);
124
+			memcpy(tdt->descriptors, &data[10], tdt->descriptors_size);
125
+		}
126
+		tdt->CRC = (tdt->CRC << 8) | data[10 + tdt->descriptors_size + 3];
127
+		tdt->CRC = (tdt->CRC << 8) | data[10 + tdt->descriptors_size + 2];
128
+		tdt->CRC = (tdt->CRC << 8) | data[10 + tdt->descriptors_size + 1];
129
+		tdt->CRC = (tdt->CRC << 8) | data[10 + tdt->descriptors_size + 0];
130
+	}
131
+
132
+	tdt->utc = ts_time_decode_mjd(tdt->mjd, tdt->bcd, &tdt->tm);
133
+
134
+	memcpy(tdt->packet_data, ts_packet, TS_PACKET_SIZE);
135
+
136
+	tdt->initialized = 1;
137
+
138
+	return 1;
139
+}
140
+
141
+void ts_tdt_generate(struct ts_tdt *tdt, uint8_t *ts_packet) {
142
+	ts_packet_header_generate(ts_packet, &tdt->ts_header);
143
+
144
+	uint8_t start = 4;
145
+	ts_packet[start + 0]  = tdt->pointer_field;
146
+	start += tdt->pointer_field + 1;
147
+
148
+	ts_packet[start + 0]  = tdt->table_id;
149
+	ts_packet[start + 1]  = tdt->section_syntax_indicator << 7;		// x1111111
150
+	ts_packet[start + 1] |= tdt->reserved_1               << 6;		// 1x111111
151
+	ts_packet[start + 1] |= tdt->reserved_2               << 4;		// 11xx1111
152
+	ts_packet[start + 1] |= tdt->section_length           >> 8;		// 1111xxxx xxxxxxxx
153
+	ts_packet[start + 2]  = tdt->section_length           &~ 0xff00;	// 1111xxxx xxxxxxxx
154
+
155
+	ts_packet[start + 3]  = (tdt->mjd &~ 0x00ff) >> 8;
156
+	ts_packet[start + 4]  = (tdt->mjd &~ 0xff00);
157
+
158
+	ts_packet[start + 5]  = (tdt->bcd >> 16);
159
+	ts_packet[start + 6]  = (tdt->bcd >> 8) &~ 0xff00;
160
+	ts_packet[start + 7]  = (tdt->bcd << 16) >> 16;
161
+
162
+	if (tdt->table_id == 0x73) { // TOT
163
+		ts_packet[start + 8]  = tdt->reserved_3 << 4;
164
+		ts_packet[start + 8] |= tdt->descriptors_size >> 8;
165
+		ts_packet[start + 9]  = tdt->descriptors_size &~ 0xf00;
166
+		if (tdt->descriptors_size) {
167
+			memcpy(&ts_packet[start + 10], tdt->descriptors, tdt->descriptors_size);
168
+		}
169
+		tdt->CRC = ts_section_data_calculate_crc(ts_packet + start, 10 + tdt->descriptors_size);
170
+	}
171
+}
172
+
173
+void ts_tdt_dump(struct ts_tdt *tdt) {
174
+	struct tm tm;
175
+	time_t ts;
176
+	uint16_t mjd_check;
177
+	uint32_t bcd_check;
178
+	char *prefix = tdt->table_id == 0x70 ? "TDT" : "TOT"; // TDT table_id == 0x70, TOT table_id == 0x73
179
+
180
+	ts = ts_time_decode_mjd(tdt->mjd, tdt->bcd, &tm);
181
+	ts_time_encode_mjd(&mjd_check, &bcd_check, &ts, &tm);
182
+
183
+	ts_LOGf("%s packet dump\n", prefix);
184
+	ts_packet_header_dump(&tdt->ts_header);
185
+	ts_LOGf("    - Table id           : %03x (%d) %s\n", tdt->table_id, tdt->table_id, prefix);
186
+	ts_LOGf("    - Section length     : %03x (%d)\n", tdt->section_length, tdt->section_length);
187
+	ts_LOGf("  * %s data\n", prefix);
188
+	ts_LOGf("    - MJD                : 0x%04x   (%04d-%02d-%02d) unixts: %ld check:0x%04x\n",
189
+		tdt->mjd,
190
+		tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
191
+		ts, mjd_check);
192
+	ts_LOGf("    - BCD                : 0x%06x (%02d:%02d:%02d) check:0x%06x\n",
193
+		tdt->bcd,
194
+		tm.tm_hour, tm.tm_min, tm.tm_sec,
195
+		bcd_check);
196
+	ts_LOGf("    - UTC Time           : %lu\n" , tdt->utc);
197
+	if (tdt->table_id == 0x73) { // TOT
198
+		if (tdt->descriptors) {
199
+			ts_descriptor_dump(tdt->descriptors, tdt->descriptors_size);
200
+		}
201
+		ts_LOGf("  * CRC 0x%04x\n", tdt->CRC);
202
+	}
203
+
204
+	ts_tdt_check_generator(tdt);
205
+}
206
+
207
+void ts_tdt_set_time(struct ts_tdt *tdt, time_t now) {
208
+	tdt->ts_header.continuity++;
209
+	ts_time_encode_mjd(&tdt->mjd, &tdt->bcd, &now, NULL);
210
+	tdt->utc = ts_time_decode_mjd(tdt->mjd, tdt->bcd, &tdt->tm);
211
+	ts_tdt_generate(tdt, tdt->packet_data);
212
+}
213
+
214
+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) {
215
+	if (tdt->table_id != 0x73)
216
+		return;
217
+	tdt->ts_header.continuity++;
218
+
219
+	ts_time_encode_mjd(&tdt->mjd, &tdt->bcd, &now, NULL);
220
+	tdt->utc = ts_time_decode_mjd(tdt->mjd, tdt->bcd, &tdt->tm);
221
+
222
+	uint16_t mjd = 0;
223
+	uint32_t bcd = 0;
224
+	ts_time_encode_mjd(&mjd, &bcd, &change_time, NULL);
225
+
226
+	uint8_t *lto; // Local time offset
227
+	if (tdt->descriptors_size == 0) {
228
+		tdt->descriptors_size = 15;
229
+		tdt->descriptors = calloc(1, tdt->descriptors_size);
230
+		tdt->section_length += tdt->descriptors_size;
231
+	}
232
+	lto = tdt->descriptors;
233
+	lto[0     ]  = 0x58;		// Descriptor tag
234
+	lto[1     ]  = 13;			// 13 octets
235
+	lto[2 +  0]  = 'B';			// Country code
236
+	lto[2 +  1]  = 'U';
237
+	lto[2 +  2]  = 'L';
238
+	lto[2 +  3]  = 0;			// 111111xx (Country region,   6 bit)
239
+	lto[2 +  3] |= bit_2;		// xxxxxx1x (Reserved,         1 bit) !!!!
240
+	lto[2 +  3] |= polarity;	// xxxxxxx1 (Polarity,         1 bit, 0 +utc, 1 -utc) !!!!
241
+
242
+	lto[2 +  4]  = ofs >> 8;	// (LocalTime offset  16 bits, bcd)
243
+	lto[2 +  5]  = ofs &~ 0xff00;
244
+
245
+	lto[2 +  6]  = mjd >> 8;	// Time of change (40 bcd)
246
+	lto[2 +  7]  = mjd &~ 0xff00;
247
+	lto[2 +  8]  = bcd >> 16;
248
+	lto[2 +  9]  = bcd >> 8;
249
+	lto[2 + 10]  = bcd &~ 0xffff00;
250
+
251
+	lto[2 + 11]  = ofs_next >> 8; // Next time offset (16 bits, bcd)
252
+	lto[2 + 12]  = ofs_next &~ 0xff00;
253
+
254
+	ts_tdt_generate(tdt, tdt->packet_data);
255
+}
256
+
257
+// Calculate change time for European summer time, see:
258
+// http://en.wikipedia.org/wiki/European_Summer_Time
259
+static time_t euro_dst_start(int year) {
260
+	struct tm tm;
261
+	int dst_start_date;
262
+	memset(&tm, 0, sizeof(struct tm));
263
+	tm.tm_year = year - 1900;
264
+	tm.tm_mon  = 2; // March
265
+	tm.tm_mday = (31 - (5 * year / 4 + 4) % 7); // Sunday DST_START March   at 01:00 GMT
266
+	tm.tm_hour = 1;
267
+	dst_start_date = timegm(&tm);
268
+	//ts_LOGf("year: %d ts: %d dst_start: %s", year, dst_start_date, asctime(&tm));
269
+	return dst_start_date;
270
+}
271
+
272
+static time_t euro_dst_end(int year) {
273
+	struct tm tm;
274
+	int dst_end_date;
275
+	memset(&tm, 0, sizeof(struct tm));
276
+	tm.tm_year = year - 1900;
277
+	tm.tm_mon  = 9; // October
278
+	tm.tm_mday = (31 - (5 * year / 4 + 1) % 7); // Sunday DST_END   October at 01:00 GMT
279
+	tm.tm_hour = 1;
280
+	dst_end_date = timegm(&tm);
281
+	//ts_LOGf("year: %d ts: %d dst_end: %s", year, dst_end_date, asctime(&tm));
282
+	return dst_end_date;
283
+}
284
+
285
+void ts_tot_set_localtime_offset_sofia(struct ts_tdt *tdt) {
286
+	time_t   now = time(NULL);
287
+	uint8_t  polarity = 0;	// 0 == UTC + offset, 1 == UTC - offset
288
+	time_t   change_time;	// When the next DST change will be
289
+	uint16_t current_offset;
290
+	uint16_t next_offset;
291
+	struct tm tm;
292
+
293
+	gmtime_r(&now, &tm);
294
+	//ts_LOGf("nowts: %d now: %s", now, asctime(&tm));
295
+	int curyear  = tm.tm_year + 1900;
296
+	int dst_start_date = euro_dst_start(curyear);
297
+	int dst_end_date   = euro_dst_end(curyear);
298
+	if (now < dst_start_date) {
299
+		current_offset = 0x0200; // We are in winter time now
300
+		next_offset    = 0x0300; // Next is the summer
301
+		change_time    = dst_start_date;
302
+	} else {
303
+		if (now >= dst_start_date && now < dst_end_date) {
304
+			current_offset = 0x0300; // We are in summer time time
305
+			next_offset    = 0x0200; // Next time it should be winter
306
+			change_time    = dst_end_date;
307
+		} else {
308
+			current_offset = 0x0200; // We are in winter time
309
+			next_offset    = 0x0300; // Next time it should be summer
310
+			change_time    = euro_dst_start(curyear + 1);
311
+		}
312
+	}
313
+	//ts_LOGf("curofs: %04x next_ofs: %04x change_time:%d\n", current_offset, next_offset, change_time);
314
+	ts_tot_set_localtime_offset(tdt, time(NULL), change_time, polarity, current_offset, next_offset);
315
+}
316
+
317
+int parse_tdt(uint8_t *ts_packet, int dump) {
318
+	struct ts_tdt *tdt = ts_tdt_alloc();
319
+	int ret = ts_tdt_parse(tdt, ts_packet);
320
+	if (ret && dump)
321
+		ts_tdt_dump(tdt);
322
+	ts_tdt_free(&tdt);
323
+	return ret;
324
+}

+ 87
- 0
tsfuncs_time.c View File

1
+#include <stdio.h>
2
+#include <unistd.h>
3
+#include <netdb.h>
4
+#include <stdlib.h>
5
+#include <string.h>
6
+#include <time.h>
7
+
8
+#include "tsfuncs.h"
9
+
10
+uint32_t ts_time_encode_bcd(int duration_sec) {
11
+	int t_sec, t_min, t_hour, ret;
12
+	t_sec  = duration_sec % 60;
13
+	t_min  = (duration_sec - t_sec) / 60;
14
+	t_hour = (t_min - t_min % 60) / 60;
15
+	t_min  = t_min - t_hour * 60;
16
+
17
+	ret  = dec2bcd(t_hour) << 16;
18
+	ret |= dec2bcd(t_min ) << 8;
19
+	ret |= dec2bcd(t_sec );
20
+
21
+	return ret;
22
+}
23
+
24
+void ts_time_decode_bcd(int duration_bcd, int *duration_sec, int *hour, int *min, int *sec) {
25
+	*hour = bcd2dec( (duration_bcd &~ 0xff00ffff) >> 16 );	// 11111111 xxxxxxxx xxxxxxxx
26
+	*min  = bcd2dec( (duration_bcd &~ 0xffff00ff) >> 8 );	// xxxxxxxx 11111111 xxxxxxxx
27
+	*sec  = bcd2dec( (duration_bcd &~ 0xffffff00) );		// xxxxxxxx xxxxxxxx 11111111
28
+	if (duration_sec)
29
+		*duration_sec = *hour * 3600 + *min * 60 + *sec;
30
+}
31
+
32
+void ts_time_encode_mjd(uint16_t *mjd, uint32_t *bcd, time_t *ts, struct tm *tm) {
33
+	struct tm *ltm = tm;
34
+	if (!ts && !tm)
35
+		return;
36
+	if (ts) { // Decompose ts into struct tm
37
+		struct tm dectm;
38
+		gmtime_r(ts, &dectm);
39
+		ltm = &dectm;
40
+	}
41
+	if (!ltm) // Paranoia
42
+		return;
43
+	if (mjd) { // Encode ymd into mjd
44
+		int Y = ltm->tm_year; // 1900 + Y gives the real year
45
+		int M = ltm->tm_mon + 1;
46
+		int D = ltm->tm_mday;
47
+		int L = (M == 1 || M == 2) ? 1 : 0;
48
+		*mjd = 14956 + D + (int)((Y - L) * 365.25) + (int)((M + 1 + L * 12) * 30.6001);
49
+	}
50
+	if (bcd) { // Encode hms into bcd
51
+		*bcd  = 0;
52
+		*bcd  = dec2bcd(ltm->tm_hour) << 16;
53
+		*bcd |= dec2bcd(ltm->tm_min ) << 8;
54
+		*bcd |= dec2bcd(ltm->tm_sec );
55
+	}
56
+}
57
+
58
+time_t ts_time_decode_mjd(uint16_t mjd, uint32_t bcd, struct tm *tm) {
59
+	int year = 0, month = 0, day = 0;
60
+	int hour = 0, min = 0, sec = 0;
61
+	time_t ret = 0;
62
+	if (mjd > 0) {
63
+		long tmp;
64
+		// Copied from ETSI EN 300 468 (ANNEX C)
65
+		year  = (int)((mjd - 15078.2) / 365.25);
66
+		month = (int)((mjd - 14956.1 - (int)(year * 365.25)) / 30.6001);
67
+		day   = mjd - 14956 - (int)(year * 365.25) - (int)(month * 30.6001);
68
+		tmp   = (month == 14 || month == 15) ? 1 : 0;
69
+		year  = year + tmp;
70
+		month = month - 1 - tmp * 12;
71
+		year  += 1900;
72
+	}
73
+	if (bcd > 0) {
74
+		ts_time_decode_bcd(bcd, NULL, &hour, &min, &sec);
75
+	}
76
+	if (tm) {
77
+		memset(tm, 0, sizeof(struct tm));
78
+		tm->tm_year = year - 1900;
79
+		tm->tm_mon  = month - 1;
80
+		tm->tm_mday = day;
81
+		tm->tm_hour = hour;
82
+		tm->tm_min  = min;
83
+		tm->tm_sec  = sec;
84
+		ret = timegm(tm);
85
+	}
86
+	return ret;
87
+}

Loading…
Cancel
Save