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

tdt_desc.c 5.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  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_alloc_init(time_t ts) {
  46. return ts_tdt_init_empty(ts_tdt_alloc(), ts, 0);
  47. }
  48. struct ts_tdt *ts_tot_alloc_init(time_t ts) {
  49. return ts_tdt_init_empty(ts_tdt_alloc(), ts, 1);
  50. }
  51. void ts_tdt_set_time(struct ts_tdt *tdt, time_t now) {
  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. ts_tdt_regenerate_packet_data(tdt);
  55. }
  56. 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) {
  57. if (tdt->section_header->table_id != 0x73)
  58. return;
  59. ts_time_encode_mjd(&tdt->mjd, &tdt->bcd, &now, NULL);
  60. tdt->utc = ts_time_decode_mjd(tdt->mjd, tdt->bcd, &tdt->tm);
  61. uint16_t mjd = 0;
  62. uint32_t bcd = 0;
  63. ts_time_encode_mjd(&mjd, &bcd, &change_time, NULL);
  64. uint8_t *lto; // Local time offset
  65. if (tdt->descriptors_size == 0) {
  66. tdt->descriptors_size = 15;
  67. tdt->descriptors = calloc(1, tdt->descriptors_size);
  68. tdt->section_header->section_length += tdt->descriptors_size;
  69. }
  70. lto = tdt->descriptors;
  71. lto[0 ] = 0x58; // Descriptor tag
  72. lto[1 ] = 13; // 13 octets
  73. lto[2 + 0] = 'B'; // Country code
  74. lto[2 + 1] = 'U';
  75. lto[2 + 2] = 'L';
  76. lto[2 + 3] = 0; // 111111xx (Country region, 6 bit)
  77. lto[2 + 3] |= bit_2; // xxxxxx1x (Reserved, 1 bit) !!!!
  78. lto[2 + 3] |= polarity; // xxxxxxx1 (Polarity, 1 bit, 0 +utc, 1 -utc) !!!!
  79. lto[2 + 4] = ofs >> 8; // (LocalTime offset 16 bits, bcd)
  80. lto[2 + 5] = ofs &~ 0xff00;
  81. lto[2 + 6] = mjd >> 8; // Time of change (40 bcd)
  82. lto[2 + 7] = mjd &~ 0xff00;
  83. lto[2 + 8] = bcd >> 16;
  84. lto[2 + 9] = bcd >> 8;
  85. lto[2 + 10] = bcd &~ 0xffff00;
  86. lto[2 + 11] = ofs_next >> 8; // Next time offset (16 bits, bcd)
  87. lto[2 + 12] = ofs_next &~ 0xff00;
  88. ts_tdt_regenerate_packet_data(tdt);
  89. }
  90. // Calculate change time for European summer time, see:
  91. // http://en.wikipedia.org/wiki/European_Summer_Time
  92. static time_t euro_dst_start(int year) {
  93. struct tm tm;
  94. int dst_start_date;
  95. memset(&tm, 0, sizeof(struct tm));
  96. tm.tm_year = year - 1900;
  97. tm.tm_mon = 2; // March
  98. tm.tm_mday = (31 - (5 * year / 4 + 4) % 7); // Sunday DST_START March at 01:00 GMT
  99. tm.tm_hour = 1;
  100. dst_start_date = timegm(&tm);
  101. //ts_LOGf("year: %d ts: %d dst_start: %s", year, dst_start_date, asctime(&tm));
  102. return dst_start_date;
  103. }
  104. static time_t euro_dst_end(int year) {
  105. struct tm tm;
  106. int dst_end_date;
  107. memset(&tm, 0, sizeof(struct tm));
  108. tm.tm_year = year - 1900;
  109. tm.tm_mon = 9; // October
  110. tm.tm_mday = (31 - (5 * year / 4 + 1) % 7); // Sunday DST_END October at 01:00 GMT
  111. tm.tm_hour = 1;
  112. dst_end_date = timegm(&tm);
  113. //ts_LOGf("year: %d ts: %d dst_end: %s", year, dst_end_date, asctime(&tm));
  114. return dst_end_date;
  115. }
  116. void ts_tot_set_localtime_offset_sofia(struct ts_tdt *tdt, time_t now) {
  117. uint8_t polarity = 0; // 0 == UTC + offset, 1 == UTC - offset
  118. time_t change_time; // When the next DST change will be
  119. uint16_t current_offset;
  120. uint16_t next_offset;
  121. struct tm tm;
  122. gmtime_r(&now, &tm);
  123. //ts_LOGf("nowts: %d now: %s", now, asctime(&tm));
  124. int curyear = tm.tm_year + 1900;
  125. int dst_start_date = euro_dst_start(curyear);
  126. int dst_end_date = euro_dst_end(curyear);
  127. if (now < dst_start_date) {
  128. current_offset = 0x0200; // We are in winter time now
  129. next_offset = 0x0300; // Next is the summer
  130. change_time = dst_start_date;
  131. } else {
  132. if (now >= dst_start_date && now < dst_end_date) {
  133. current_offset = 0x0300; // We are in summer time time
  134. next_offset = 0x0200; // Next time it should be winter
  135. change_time = dst_end_date;
  136. } else {
  137. current_offset = 0x0200; // We are in winter time
  138. next_offset = 0x0300; // Next time it should be summer
  139. change_time = euro_dst_start(curyear + 1);
  140. }
  141. }
  142. //ts_LOGf("curofs: %04x next_ofs: %04x change_time:%d\n", current_offset, next_offset, change_time);
  143. ts_tot_set_localtime_offset(tdt, now, change_time, polarity, current_offset, next_offset);
  144. }