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 5.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  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->section_header = ts_section_data_alloc();
  11. return tdt;
  12. }
  13. void ts_tdt_free(struct ts_tdt **ptdt) {
  14. struct ts_tdt *tdt = *ptdt;
  15. if (tdt) {
  16. ts_section_data_free(&tdt->section_header);
  17. FREE(tdt->descriptors);
  18. FREE(*ptdt);
  19. }
  20. }
  21. static struct ts_tdt *ts_tdt_reset(struct ts_tdt *tdt) {
  22. struct ts_tdt *newtdt = ts_tdt_alloc();
  23. ts_tdt_free(&tdt);
  24. return newtdt;
  25. }
  26. struct ts_tdt *ts_tdt_push_packet(struct ts_tdt *tdt, uint8_t *ts_packet) {
  27. struct ts_header ts_header;
  28. memset(&ts_header, 0, sizeof(struct ts_header));
  29. if (ts_packet_header_parse(ts_packet, &ts_header)) {
  30. // TDT/TOT should be with PID 0x11
  31. if (ts_header.pid != 0x14)
  32. goto OUT;
  33. if (!tdt->ts_header.pusi)
  34. tdt->ts_header = ts_header;
  35. }
  36. if (ts_header.pusi) {
  37. struct ts_section_header section_header;
  38. memset(&section_header, 0, sizeof(struct ts_section_header));
  39. uint8_t *section_data = ts_section_header_parse(ts_packet, &tdt->ts_header, &section_header);
  40. if (!section_data) {
  41. memset(&tdt->ts_header, 0, sizeof(struct ts_header));
  42. goto OUT;
  43. }
  44. // table_id should be 0x70 (time_date_section)
  45. // or table_id should be 0x73 (time_offset_section)
  46. if (section_header.table_id != 0x70 && section_header.table_id != 0x73) {
  47. memset(&tdt->ts_header, 0, sizeof(struct ts_header));
  48. goto OUT;
  49. }
  50. // Set correct section_header
  51. ts_section_header_parse(ts_packet, &tdt->ts_header, tdt->section_header);
  52. }
  53. if (!tdt->initialized) {
  54. ts_section_add_packet(tdt->section_header, &ts_header, ts_packet);
  55. if (tdt->section_header->initialized) {
  56. if (!ts_tdt_parse(tdt))
  57. goto ERROR;
  58. }
  59. }
  60. OUT:
  61. return tdt;
  62. ERROR:
  63. return ts_tdt_reset(tdt);
  64. }
  65. int ts_tdt_parse(struct ts_tdt *tdt) {
  66. struct ts_section_header *sec = tdt->section_header;
  67. uint8_t *data = sec->data;
  68. tdt->mjd = (data[0] << 8) | data[1];
  69. tdt->bcd = ((data[2] << 16) | (data[3] << 8)) | data[4];
  70. data += 5;
  71. tdt->utc = ts_time_decode_mjd(tdt->mjd, tdt->bcd, &tdt->tm);
  72. if (sec->table_id == 0x73) { // TOT
  73. tdt->reserved_3 = data[0] >> 4; // xxxx1111
  74. tdt->descriptors_size = data[0] &~ 0xf0; // 1111xxxx
  75. tdt->descriptors_size |= data[1]; // xxxxxxxx
  76. data += 2;
  77. if (tdt->descriptors_size) {
  78. tdt->descriptors = malloc(tdt->descriptors_size);
  79. memcpy(tdt->descriptors, data, tdt->descriptors_size);
  80. }
  81. if (!ts_crc32_section_check(tdt->section_header, "TOT"))
  82. return 0;
  83. }
  84. tdt->initialized = 1;
  85. return 1;
  86. }
  87. void ts_tdt_generate(struct ts_tdt *tdt, uint8_t **ts_packets, int *num_packets) {
  88. uint8_t *secdata = ts_section_data_alloc_section();
  89. ts_section_header_generate(secdata, tdt->section_header, 0);
  90. int curpos = 3; // Compensate for the section header, first data byte is at offset 3
  91. secdata[curpos + 0] = (tdt->mjd &~ 0x00ff) >> 8;
  92. secdata[curpos + 1] = (tdt->mjd &~ 0xff00);
  93. secdata[curpos + 2] = (tdt->bcd >> 16);
  94. secdata[curpos + 3] = (tdt->bcd >> 8) &~ 0xff00;
  95. secdata[curpos + 4] = (tdt->bcd << 16) >> 16;
  96. curpos += 5; // For the fields above
  97. if (tdt->section_header->table_id == 0x73) { // TOT
  98. secdata[curpos + 0] = tdt->reserved_3 << 4;
  99. secdata[curpos + 0] |= tdt->descriptors_size >> 8;
  100. secdata[curpos + 1] = tdt->descriptors_size &~ 0xf00;
  101. curpos += 2;
  102. if (tdt->descriptors_size > 0) {
  103. memcpy(secdata + curpos, tdt->descriptors, tdt->descriptors_size);
  104. curpos += tdt->descriptors_size;
  105. }
  106. tdt->section_header->CRC = ts_section_data_calculate_crc(secdata, curpos);
  107. curpos += 4; // CRC
  108. }
  109. ts_section_data_gen_ts_packets(&tdt->ts_header, secdata, curpos, tdt->section_header->pointer_field, ts_packets, num_packets);
  110. FREE(secdata);
  111. }
  112. void ts_tdt_check_generator(struct ts_tdt *tdt) {
  113. struct ts_tdt *tdt1 = ts_tdt_alloc();
  114. int i;
  115. char *prefix1 = "TDT (tspacket->struct)";
  116. char *prefix2 = "TDT (struct->tspacket)";
  117. if (tdt->section_header->table_id == 0x73) {
  118. prefix1[1] = 'O';
  119. prefix2[1] = 'O';
  120. }
  121. for (i=0;i<tdt->section_header->num_packets;i++) {
  122. tdt1 = ts_tdt_push_packet(tdt1, tdt->section_header->packet_data + (i * TS_PACKET_SIZE));
  123. }
  124. ts_compare_data(prefix1, // "TDT (tspacket->struct)",
  125. tdt1->section_header->packet_data,
  126. tdt->section_header->packet_data,
  127. tdt->section_header->num_packets * TS_PACKET_SIZE);
  128. ts_tdt_free(&tdt1);
  129. uint8_t *ts_packets;
  130. int num_packets;
  131. ts_tdt_generate(tdt, &ts_packets, &num_packets);
  132. if (num_packets != tdt->section_header->num_packets) {
  133. ts_LOGf("ERROR: num_packets:%d != sec->num_packets:%d\n", num_packets, tdt->section_header->num_packets);
  134. }
  135. ts_compare_data(prefix2 /* "TDT (struct->tspacket)" */, tdt->section_header->packet_data, ts_packets, num_packets * TS_PACKET_SIZE);
  136. free(ts_packets);
  137. }
  138. void ts_tdt_dump(struct ts_tdt *tdt) {
  139. struct ts_section_header *sec = tdt->section_header;
  140. struct tm tm;
  141. time_t ts;
  142. uint16_t mjd_check;
  143. uint32_t bcd_check;
  144. ts_section_dump(sec);
  145. ts = ts_time_decode_mjd(tdt->mjd, tdt->bcd, &tm);
  146. ts_time_encode_mjd(&mjd_check, &bcd_check, &ts, &tm);
  147. ts_LOGf(" * %s data\n", sec->table_id == 0x70 ? "TDT" : "TOT");
  148. ts_LOGf(" - MJD : 0x%04x (%04d-%02d-%02d) unixts: %ld check:0x%04x\n",
  149. tdt->mjd,
  150. tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
  151. ts, mjd_check);
  152. ts_LOGf(" - BCD : 0x%06x (%02d:%02d:%02d) check:0x%06x\n",
  153. tdt->bcd,
  154. tm.tm_hour, tm.tm_min, tm.tm_sec,
  155. bcd_check);
  156. ts_LOGf(" - UTC Time : %lu (%04d-%02d-%02d %02d:%02d:%02d)\n" , tdt->utc,
  157. tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
  158. tm.tm_hour, tm.tm_min, tm.tm_sec);
  159. if (sec->table_id == 0x73 && tdt->descriptors_size) { // TOT
  160. ts_descriptor_dump(tdt->descriptors, tdt->descriptors_size);
  161. }
  162. ts_tdt_check_generator(tdt);
  163. }