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.

tdt_desc.c 5.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  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. static void ts_tdt_regenerate_packet_data(struct ts_tdt *tdt) {
  9. uint8_t *ts_packets;
  10. int num_packets;
  11. ts_tdt_generate(tdt, &ts_packets, &num_packets);
  12. memcpy(tdt->section_header->packet_data, ts_packets, num_packets * TS_PACKET_SIZE);
  13. tdt->section_header->num_packets = num_packets;
  14. free(ts_packets);
  15. }
  16. static struct ts_tdt *ts_tdt_init_empty(struct ts_tdt *tdt, time_t ts, int tot) {
  17. tdt->ts_header.pid = 0x14;
  18. tdt->ts_header.pusi = 1;
  19. tdt->ts_header.payload_field = 1;
  20. tdt->ts_header.payload_offset = 4;
  21. tdt->section_header->table_id = 0x70;
  22. tdt->section_header->section_syntax_indicator = 0;
  23. tdt->section_header->private_indicator = 1;
  24. tdt->section_header->reserved1 = 3;
  25. tdt->section_header->section_length = 5; // 5 bytes UTC_time
  26. ts_time_encode_mjd(&tdt->mjd, &tdt->bcd, &ts, NULL);
  27. tdt->utc = ts_time_decode_mjd(tdt->mjd, tdt->bcd, &tdt->tm);
  28. if (tot) {
  29. tdt->section_header->table_id = 0x73;
  30. tdt->section_header->section_length = 5 + 2 + 4; // 5 bytes UTC_time, 2 bytes reserved & descripts_size, 4 bytes CRC
  31. tdt->reserved_3 = 0xf;
  32. tdt->descriptors_size = 0;
  33. }
  34. tdt->initialized = 1;
  35. ts_tdt_regenerate_packet_data(tdt);
  36. return tdt;
  37. }
  38. struct ts_tdt *ts_tdt_alloc_init(time_t ts) {
  39. return ts_tdt_init_empty(ts_tdt_alloc(), ts, 0);
  40. }
  41. struct ts_tdt *ts_tot_alloc_init(time_t ts) {
  42. return ts_tdt_init_empty(ts_tdt_alloc(), ts, 1);
  43. }
  44. void ts_tdt_set_time(struct ts_tdt *tdt, time_t now) {
  45. ts_time_encode_mjd(&tdt->mjd, &tdt->bcd, &now, NULL);
  46. tdt->utc = ts_time_decode_mjd(tdt->mjd, tdt->bcd, &tdt->tm);
  47. ts_tdt_regenerate_packet_data(tdt);
  48. }
  49. 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) {
  50. if (tdt->section_header->table_id != 0x73)
  51. return;
  52. ts_time_encode_mjd(&tdt->mjd, &tdt->bcd, &now, NULL);
  53. tdt->utc = ts_time_decode_mjd(tdt->mjd, tdt->bcd, &tdt->tm);
  54. uint16_t mjd = 0;
  55. uint32_t bcd = 0;
  56. ts_time_encode_mjd(&mjd, &bcd, &change_time, NULL);
  57. uint8_t *lto; // Local time offset
  58. if (tdt->descriptors_size == 0) {
  59. tdt->descriptors_size = 15;
  60. tdt->descriptors = calloc(1, tdt->descriptors_size);
  61. tdt->section_header->section_length += tdt->descriptors_size;
  62. }
  63. lto = tdt->descriptors;
  64. lto[0 ] = 0x58; // Descriptor tag
  65. lto[1 ] = 13; // 13 octets
  66. lto[2 + 0] = 'B'; // Country code
  67. lto[2 + 1] = 'U';
  68. lto[2 + 2] = 'L';
  69. lto[2 + 3] = 0; // 111111xx (Country region, 6 bit)
  70. lto[2 + 3] |= bit_2; // xxxxxx1x (Reserved, 1 bit) !!!!
  71. lto[2 + 3] |= polarity; // xxxxxxx1 (Polarity, 1 bit, 0 +utc, 1 -utc) !!!!
  72. lto[2 + 4] = ofs >> 8; // (LocalTime offset 16 bits, bcd)
  73. lto[2 + 5] = ofs &~ 0xff00;
  74. lto[2 + 6] = mjd >> 8; // Time of change (40 bcd)
  75. lto[2 + 7] = mjd &~ 0xff00;
  76. lto[2 + 8] = bcd >> 16;
  77. lto[2 + 9] = bcd >> 8;
  78. lto[2 + 10] = bcd &~ 0xffff00;
  79. lto[2 + 11] = ofs_next >> 8; // Next time offset (16 bits, bcd)
  80. lto[2 + 12] = ofs_next &~ 0xff00;
  81. ts_tdt_regenerate_packet_data(tdt);
  82. }
  83. // Calculate change time for European summer time, see:
  84. // http://en.wikipedia.org/wiki/European_Summer_Time
  85. static time_t euro_dst_start(int year) {
  86. struct tm tm;
  87. int dst_start_date;
  88. memset(&tm, 0, sizeof(struct tm));
  89. tm.tm_year = year - 1900;
  90. tm.tm_mon = 2; // March
  91. tm.tm_mday = (31 - (5 * year / 4 + 4) % 7); // Sunday DST_START March at 01:00 GMT
  92. tm.tm_hour = 1;
  93. dst_start_date = timegm(&tm);
  94. //ts_LOGf("year: %d ts: %d dst_start: %s", year, dst_start_date, asctime(&tm));
  95. return dst_start_date;
  96. }
  97. static time_t euro_dst_end(int year) {
  98. struct tm tm;
  99. int dst_end_date;
  100. memset(&tm, 0, sizeof(struct tm));
  101. tm.tm_year = year - 1900;
  102. tm.tm_mon = 9; // October
  103. tm.tm_mday = (31 - (5 * year / 4 + 1) % 7); // Sunday DST_END October at 01:00 GMT
  104. tm.tm_hour = 1;
  105. dst_end_date = timegm(&tm);
  106. //ts_LOGf("year: %d ts: %d dst_end: %s", year, dst_end_date, asctime(&tm));
  107. return dst_end_date;
  108. }
  109. void ts_tot_set_localtime_offset_sofia(struct ts_tdt *tdt, time_t now) {
  110. uint8_t polarity = 0; // 0 == UTC + offset, 1 == UTC - offset
  111. time_t change_time; // When the next DST change will be
  112. uint16_t current_offset;
  113. uint16_t next_offset;
  114. struct tm tm;
  115. gmtime_r(&now, &tm);
  116. //ts_LOGf("nowts: %d now: %s", now, asctime(&tm));
  117. int curyear = tm.tm_year + 1900;
  118. int dst_start_date = euro_dst_start(curyear);
  119. int dst_end_date = euro_dst_end(curyear);
  120. if (now < dst_start_date) {
  121. current_offset = 0x0200; // We are in winter time now
  122. next_offset = 0x0300; // Next is the summer
  123. change_time = dst_start_date;
  124. } else {
  125. if (now >= dst_start_date && now < dst_end_date) {
  126. current_offset = 0x0300; // We are in summer time time
  127. next_offset = 0x0200; // Next time it should be winter
  128. change_time = dst_end_date;
  129. } else {
  130. current_offset = 0x0200; // We are in winter time
  131. next_offset = 0x0300; // Next time it should be summer
  132. change_time = euro_dst_start(curyear + 1);
  133. }
  134. }
  135. //ts_LOGf("curofs: %04x next_ofs: %04x change_time:%d\n", current_offset, next_offset, change_time);
  136. ts_tot_set_localtime_offset(tdt, now, change_time, polarity, current_offset, next_offset);
  137. }