2 * Decode SDT and NIT from a TS stream (for instance dvr0), and output in a
3 * relatively machine-readable format.
5 * Based on the decode_sdt.c example from libdvbpsi, and uses some source code
10 * Dave Chapman <dave@dchapman.com> 2001, 2002.
11 * 2004-2011 Brice DUBOST
12 * 2013 Steinar H. Gunderson
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
40 #include <dvbpsi/dvbpsi.h>
41 #include <dvbpsi/psi.h>
42 #include <dvbpsi/demux.h>
43 #include <dvbpsi/descriptor.h>
44 #include <dvbpsi/sdt.h>
45 #include <dvbpsi/nit.h>
49 static int packet_num = 0;
50 static int last_used_packet_num = 0;
57 bool operator< (const channel_id &other) const {
58 if (i_network_id != other.i_network_id)
59 return (i_network_id < other.i_network_id);
60 if (i_service_id != other.i_service_id)
61 return (i_service_id < other.i_service_id);
62 return (i_extension < other.i_extension);
67 @brief The different encodings that can be used
68 Cf EN 300 468 Annex A (I used v1.9.1)
70 static const char *encodings_en300468[] ={
86 "ISO-10646", //control char 0x11
87 "GB2312", //control char 0x13
88 "BIG5", //control char 0x14
89 "ISO-10646/UTF8", //control char 0x15
92 // Convert text according to EN 300 468 annex A.
93 static int convert_en300468_string(char *string, int max_len)
95 int encoding_control_char = 8; //cf encodings_en300468
97 char *tempdest, *tempbuf;
99 /* remove control characters and convert to UTF-8 the channel name */
100 //If no channel encoding is specified, it seems that most of the broadcasters
101 //uses ISO/IEC 8859-9. But the norm (EN 300 468) said that it should be Latin-1 (ISO/IEC 6937 + euro)
103 //temporary buffers allocation
104 tempdest = tempbuf = (char *)malloc(sizeof(char)*2*strlen(string));
105 if (tempdest==NULL) {
110 for (src = (unsigned char *)string; *src; src++) {
111 if (*src >= 0x20 && (*src < 0x80 || *src > 0x9f)) {
112 //We copy non-control characters
115 } else if (*src <= 0x20) {
116 //control character recognition based on EN 300 468 v1.9.1 Annex A
118 encoding_control_char=(int) *src+4-1;
119 } else if(*src == 0x10) { //ISO/IEC 8859 : See table A.4
120 src++;//we skip the current byte
121 src++;//This one is always set to 0
122 if (*src >= 0x01 && *src <=0x0f)
123 encoding_control_char=(int) *src-1;
125 else if (*src==0x11) // ISO/IEC 10646 : Basic Multilingual Plane
126 encoding_control_char = 15;
127 else if (*src==0x13) // GB-2312-1980 : Simplified Chinese Character
128 encoding_control_char = 16;
129 else if (*src==0x14) // Big5 subset of ISO/IEC 10646 : Traditional Chinese
130 encoding_control_char = 17;
131 else if (*src==0x15) // UTF-8 encoding of ISO/IEC 10646 : Basic Multilingual Plane
132 encoding_control_char = 18;
137 //we open the conversion table
138 cd = iconv_open("UTF8", encodings_en300468[encoding_control_char]);
140 size_t inSize, outSize = max_len;
142 //pointers initialisation because iconv change them, we store
146 iconv(cd, &tempdest, &inSize, &dest, &outSize);
151 return encoding_control_char;
155 static bool ReadPacket(int i_fd, uint8_t * p_dst)
157 static uint8_t buf[188 * 100];
158 static int in_buf_start = 0;
159 static int in_buf_end = 0;
162 // Skip to the first 0x47 byte.
163 while (in_buf_end > in_buf_start && buf[in_buf_start] != 0x47) {
167 if (in_buf_end - in_buf_start >= 188) {
168 memcpy(p_dst, buf + in_buf_start, 188);
173 // Check if there's a partial packet in the buffer.
174 int partial_len = in_buf_end - in_buf_start;
175 if (partial_len == 0) {
176 in_buf_start = in_buf_end = 0;
177 } else if (partial_len > 0) {
178 memmove(buf, buf + in_buf_start, partial_len);
180 in_buf_end = partial_len;
183 int ret = read(i_fd, buf + in_buf_start, sizeof(buf) - in_buf_end);
198 static void ParseSDT(void *p_zero, dvbpsi_sdt_t * p_sdt)
200 dvbpsi_sdt_service_t *p_service = p_sdt->p_first_service;
201 for (dvbpsi_sdt_service_t * p_service = p_sdt->p_first_service;
203 p_service = p_service->p_next) {
204 int service_type = -1;
205 char provider_name[256] = { 0 };
206 char channel_name[256] = { 0 };
207 dvbpsi_descriptor_t *p_descriptor =
208 p_service->p_first_descriptor;
210 // Search for a Service Descriptor (0x48), which contains the provider and channel names.
211 for (dvbpsi_descriptor_t * p_descriptor = p_service->p_first_descriptor;
212 p_descriptor != NULL;
213 p_descriptor = p_descriptor->p_next) {
216 if (p_descriptor->i_tag != 0x48) {
219 service_type = p_descriptor->p_data[0];
220 ptr = p_descriptor->p_data + 1;
223 memcpy(provider_name, ptr, len);
224 provider_name[len] = 0;
228 memcpy(channel_name, ptr, len);
229 channel_name[len] = 0;
231 convert_en300468_string(provider_name, sizeof(provider_name));
232 convert_en300468_string(channel_name, sizeof(channel_name));
235 // Show television types only.
236 if (service_type == 0x01 || service_type == 0x11 || service_type == 0x16 ||
237 service_type == 0x19 || service_type == 0x1c) {
238 // Do our own deduplication, since libdvbpsi only deduplicates against
239 // the last version seen, not the entire history.
240 static std::set<channel_id> seen_channels;
241 channel_id id = { p_sdt->i_network_id, p_service->i_service_id, p_sdt->i_extension };
242 if (seen_channels.insert(id).second) {
243 last_used_packet_num = packet_num;
244 printf("sid %d/%d: ts_id=%d, provider_name=\"%s\", channel_name=\"%s\"\n",
245 p_sdt->i_network_id, p_service->i_service_id,
246 p_sdt->i_extension, provider_name,
251 dvbpsi_sdt_delete(p_sdt);
254 // little endian assumed
260 uint16_t orbital_position; // big-endian
261 uint8_t modulation_type : 2;
262 uint8_t modulation_system : 1;
263 uint8_t roll_off : 2;
264 uint8_t polarization : 2;
265 uint8_t west_east_flag : 1;
266 uint8_t symbol_rate_12;
267 uint8_t symbol_rate_34;
268 uint8_t symbol_rate_56;
269 uint8_t FEC_inner : 4;
270 uint8_t symbol_rate_7 : 4;
271 } descr_sat_delivery_t;
273 // Canal Digital stores their LCN in the NIT (Wikipedia says some do it in
274 // the BAT). I haven't been able to find any format for this, even in NorDIG's
275 // specification, so this is done by visual inspection.
276 static void ParseLCN(int network_id, const dvbpsi_descriptor_t *p_descriptor)
278 uint8_t *ptr = p_descriptor->p_data;
279 int channel_list_id = *ptr++;
281 // Skip the name and the three-letter country code.
287 for (int i = 0; i < len; i += 4) {
288 int sid = (ptr[i] << 8) | ptr[i + 1];
289 int lcn = ((ptr[i + 2] << 8) | ptr[i + 3]) & 0x3fff;
290 printf("lcn %d/%d/%d: lcn=%d\n", network_id, channel_list_id, sid, lcn);
294 static void ParseDSD(const dvbpsi_nit_t *p_nit, const dvbpsi_nit_ts_t *p_ts, const dvbpsi_descriptor_t *p_descriptor)
298 descr_sat_delivery_t *d =
299 (descr_sat_delivery_t *) p_descriptor->p_data;
300 printf("ts %d/%d: ", p_nit->i_network_id, p_ts->i_ts_id);
301 printf("freq=%x%02x%02x, ", d->frequency_4,
302 d->frequency_3, d->frequency_2,
304 printf("pol=%c, ", "HVLR"[d->polarization]);
305 if (d->modulation_system) {
306 printf("delivery_system=DVBS2, ");
308 printf("delivery_system=DVBS, ");
310 if (d->modulation_type == 0) {
311 printf("modulation=QAMAUTO, ");
312 } else if (d->modulation_type == 1) {
313 printf("modulation=QPSK, ");
314 } else if (d->modulation_type == 2) {
315 printf("modulation=8PSK, ");
316 } else if (d->modulation_type == 3) {
317 printf("modulation=QAM64, ");
319 printf("srate=%x%02x%02x, ", d->symbol_rate_12, d->symbol_rate_34, d->symbol_rate_56);
320 if (d->FEC_inner == 0) {
321 printf("coderate=auto");
322 } else if (d->FEC_inner == 1) {
323 printf("coderate=1/2");
324 } else if (d->FEC_inner == 2) {
325 printf("coderate=2/3");
326 } else if (d->FEC_inner == 3) {
327 printf("coderate=3/4");
328 } else if (d->FEC_inner == 4) {
329 printf("coderate=5/6");
330 } else if (d->FEC_inner == 5) {
331 printf("coderate=7/8");
332 } else if (d->FEC_inner == 6) {
333 printf("coderate=8/9");
334 } else if (d->FEC_inner == 7) {
335 printf("coderate=3/5");
336 } else if (d->FEC_inner == 8) {
337 printf("coderate=4/5");
338 } else if (d->FEC_inner == 9) {
339 printf("coderate=9/10");
341 printf("coderate=none");
346 static void ParseNIT(void *p_zero, dvbpsi_nit_t * p_nit)
348 last_used_packet_num = packet_num;
349 for (dvbpsi_nit_ts_t *p_ts = p_nit->p_first_ts;
351 p_ts = p_ts->p_next) {
352 // Search through the descriptors until we find one of type 0x43
353 // (Delivery System Descriptor).
354 for (dvbpsi_descriptor_t *p_descriptor = p_ts->p_first_descriptor;
355 p_descriptor != NULL;
356 p_descriptor = p_descriptor->p_next) {
357 if (p_descriptor->i_tag == 0x87) {
358 ParseLCN(p_nit->i_network_id, p_descriptor);
360 if (p_descriptor->i_tag == 0x43) {
361 ParseDSD(p_nit, p_ts, p_descriptor);
365 dvbpsi_nit_delete(p_nit);
368 /*****************************************************************************
369 * DVBPSI messaging callback
370 *****************************************************************************/
371 static void message(dvbpsi_t * handle, const dvbpsi_msg_level_t level,
375 case DVBPSI_MSG_ERROR:
376 fprintf(stderr, "Error: ");
378 case DVBPSI_MSG_WARN:
379 fprintf(stderr, "Warning: ");
381 case DVBPSI_MSG_DEBUG:
382 fprintf(stderr, "Debug: ");
384 default: /* do nothing */
387 fprintf(stderr, "%s\n", msg);
390 /*****************************************************************************
392 *****************************************************************************/
393 static void NewSubtableNIT(dvbpsi_t * p_dvbpsi, uint8_t i_table_id,
394 uint16_t i_extension, void *p_zero)
396 if (i_table_id == 0x40) {
397 if (!dvbpsi_nit_attach(p_dvbpsi, i_table_id, i_extension, ParseNIT, NULL))
398 fprintf(stderr, "Failed to attach PSI subdecoder\n");
402 /*****************************************************************************
404 *****************************************************************************/
405 static void NewSubtableSDT(dvbpsi_t * p_dvbpsi, uint8_t i_table_id,
406 uint16_t i_extension, void *p_zero)
408 if (i_table_id == 0x42 || i_table_id == 0x46) {
409 if (!dvbpsi_sdt_attach(p_dvbpsi, i_table_id, i_extension, ParseSDT, NULL))
410 fprintf(stderr, "Failed to attach SDT subdecoder\n");
414 /*****************************************************************************
416 *****************************************************************************/
417 int main(int i_argc, char *pa_argv[])
421 dvbpsi_t *p_dvbpsi_sdt, *p_dvbpsi_nit;
427 i_fd = open(pa_argv[1], 0);
431 p_dvbpsi_sdt = dvbpsi_new(&message, DVBPSI_MSG_ERROR);
432 if (p_dvbpsi_sdt == NULL)
435 p_dvbpsi_nit = dvbpsi_new(&message, DVBPSI_MSG_ERROR);
436 if (p_dvbpsi_nit == NULL)
439 if (!dvbpsi_AttachDemux(p_dvbpsi_sdt, NewSubtableSDT, NULL))
442 if (!dvbpsi_AttachDemux(p_dvbpsi_nit, NewSubtableNIT, NULL))
445 while (ReadPacket(i_fd, data)) {
446 uint16_t i_pid = ((uint16_t)(data[1] & 0x1f) << 8) + data[2];
448 dvbpsi_packet_push(p_dvbpsi_nit, data);
450 dvbpsi_packet_push(p_dvbpsi_sdt, data);
452 // After 100k packets with no new information, we assume we are done.
454 if ((packet_num - last_used_packet_num) >= 100000)
460 dvbpsi_DetachDemux(p_dvbpsi_sdt);
461 dvbpsi_delete(p_dvbpsi_sdt);
464 dvbpsi_DetachDemux(p_dvbpsi_nit);
465 dvbpsi_delete(p_dvbpsi_nit);