libtsfuncs is a library for mpeg PSI parsing and generation. https://georgi.unixsol.org/programs/libtsfuncs/

tdt_desc.c 5.6KB

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