libtsfuncs is a library for mpeg PSI parsing and generation. https://georgi.unixsol.org/programs/libtsfuncs/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

tsfuncs_tdt.c 10KB

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