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

sections.c 8.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. /*
  2. * PSI Section functions
  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 <ctype.h>
  14. #include "tsfuncs.h"
  15. #define have_left(X) \
  16. do { if (data + (X) > data_end) return NULL; } while(0)
  17. void ts_section_header_set_private_vars(struct ts_section_header *ts_section_header) {
  18. if (ts_section_header->section_syntax_indicator) {
  19. ts_section_header->data = ts_section_header->section_data + 3 + 5; // Skip header and extended header
  20. ts_section_header->data_len = ts_section_header->section_length - 9; // 5 for extended header, 4 for crc at the end
  21. } else {
  22. ts_section_header->data = ts_section_header->section_data + 3; // Skip header
  23. ts_section_header->data_len = ts_section_header->section_length;
  24. }
  25. ts_section_header->section_data_len = ts_section_header->section_length + 3; // 3 for section header
  26. }
  27. uint8_t *ts_section_header_parse(uint8_t *ts_packet, struct ts_header *ts_header, struct ts_section_header *ts_section_header) {
  28. uint8_t *data = ts_packet + ts_header->payload_offset;
  29. uint8_t *data_end = ts_packet + TS_PACKET_SIZE;
  30. have_left(ts_section_header->pointer_field + 1);
  31. ts_section_header->pointer_field = data[0];
  32. data += ts_section_header->pointer_field + 1;
  33. have_left(3);
  34. ts_section_header->table_id = data[0];
  35. ts_section_header->section_syntax_indicator = data[1] >> 7; // x1111111
  36. ts_section_header->private_indicator = (data[1] &~ 0xBF) >> 6; // 1x111111
  37. ts_section_header->reserved1 = (data[1] &~ 0xCF) >> 4; // 11xx1111
  38. ts_section_header->section_length = ((data[1] &~ 0xF0) << 8) | data[2]; // 1111xxxx xxxxxxxx
  39. data += 3;
  40. if (ts_section_header->section_length == 0)
  41. return NULL;
  42. // Stuffing table, ignore.
  43. if (ts_section_header->table_id == 0x72)
  44. return NULL;
  45. if (ts_section_header->section_syntax_indicator) {
  46. have_left(5);
  47. ts_section_header->ts_id_number = (data[0] << 8) | data[1]; // xxxxxxx xxxxxxx
  48. ts_section_header->reserved2 = data[2] >> 6; // xx111111
  49. ts_section_header->version_number = (data[2] &~ 0xC1) >> 1; // 11xxxxx1
  50. ts_section_header->current_next_indicator = data[2] &~ 0xFE; // 1111111x
  51. ts_section_header->section_number = data[3];
  52. ts_section_header->last_section_number = data[4];
  53. data += 5;
  54. }
  55. ts_section_header_set_private_vars(ts_section_header);
  56. return data;
  57. }
  58. #undef have_left
  59. void ts_section_header_generate(uint8_t *ts_packet, struct ts_section_header *ts_section_header, uint8_t start) {
  60. ts_packet[start + 0] = ts_section_header->table_id;
  61. ts_packet[start + 1] = ts_section_header->section_syntax_indicator << 7; // x1111111
  62. ts_packet[start + 1] |= ts_section_header->private_indicator << 6; // 1x111111
  63. ts_packet[start + 1] |= ts_section_header->reserved1 << 4; // 11xx1111
  64. ts_packet[start + 1] |= ts_section_header->section_length >> 8; // 1111xxxx xxxxxxxx
  65. ts_packet[start + 2] = ts_section_header->section_length &~ 0xff00; // 1111xxxx xxxxxxxx
  66. if (ts_section_header->section_syntax_indicator) { // Extended table syntax
  67. ts_packet[start + 3] = ts_section_header->ts_id_number >> 8; // xxxxxxxx xxxxxxxx
  68. ts_packet[start + 4] = ts_section_header->ts_id_number &~ 0xff00;
  69. ts_packet[start + 5] = ts_section_header->reserved2 << 6; // xx111111
  70. ts_packet[start + 5] |= ts_section_header->version_number << 1; // 11xxxxx1
  71. ts_packet[start + 5] |= ts_section_header->current_next_indicator; // 1111111x
  72. ts_packet[start + 6] = ts_section_header->section_number;
  73. ts_packet[start + 7] = ts_section_header->last_section_number;
  74. }
  75. }
  76. int ts_section_is_same(struct ts_section_header *s1, struct ts_section_header *s2) {
  77. // ts_LOGf("s1->table_id=%d s2->table_id=%d\n", s1->table_id, s2->table_id);
  78. if (s1->table_id != s2->table_id)
  79. return 0;
  80. // ts_LOGf("s1->version_number=%d s2->version_number=%d\n", s1->version_number, s2->version_number);
  81. if (s1->version_number != s2->version_number)
  82. return 0;
  83. // ts_LOGf("s1->section_number=%d s2->section_number=%d\n", s1->section_number, s2->section_number);
  84. if (s1->section_number != s2->section_number)
  85. return 0;
  86. // ts_LOGf("s1->section_length=%d s2->section_length=%d\n", s1->section_number, s2->section_number);
  87. if (s1->section_length != s2->section_length)
  88. return 0;
  89. return memcmp(s1->section_data, s2->section_data, s1->section_length) == 0;
  90. }
  91. #define IN(x, a, b) \
  92. (x >= a && x <= b)
  93. void ts_section_header_dump(struct ts_section_header *t) {
  94. ts_LOGf("%s", " * Section header\n");
  95. if (t->pointer_field)
  96. ts_LOGf(" - Pointer field : %d\n", t->pointer_field);
  97. ts_LOGf(" - Table id : %03x (%d) %s\n", t->table_id, t->table_id,
  98. t->table_id == 0x00 ? "program_association_section" :
  99. t->table_id == 0x01 ? "conditional_access_section" :
  100. t->table_id == 0x02 ? "program_map_section" :
  101. t->table_id == 0x03 ? "transport_stream_description_section" :
  102. IN(t->table_id, 0x04, 0x3f) ? "reserved" :
  103. t->table_id == 0x40 ? "network_information_section - actual_network" :
  104. t->table_id == 0x41 ? "network_information_section - other_network" :
  105. t->table_id == 0x42 ? "service_description_section - actual_transport_stream" :
  106. t->table_id == 0x83 ? "lcn_description_section - other" :
  107. IN(t->table_id, 0x43, 0x45) ? "reserved for future use" :
  108. t->table_id == 0x46 ? "service_description_section - other_transport_stream" :
  109. IN(t->table_id, 0x47, 0x49) ? "reserved for future use" :
  110. t->table_id == 0x4a ? "bouquet_association_section" :
  111. IN(t->table_id, 0x4b, 0x4d) ? "reserved for future use" :
  112. t->table_id == 0x4e ? "event_information_section - actual_transport_stream, present/following" :
  113. t->table_id == 0x4f ? "event_information_section - other_transport_stream, present/following" :
  114. IN(t->table_id, 0x50, 0x5f) ? "event_information_section - actual_transport_stream, schedule" :
  115. IN(t->table_id, 0x60, 0x6f) ? "event_information_section - other_transport_stream, schedule" :
  116. t->table_id == 0x70 ? "time_date_section" :
  117. t->table_id == 0x71 ? "running_status_section" :
  118. t->table_id == 0x72 ? "stuffing_section" :
  119. t->table_id == 0x73 ? "time_offset_section" :
  120. t->table_id == 0x74 ? "application information section (TS 102 812 [15])" :
  121. t->table_id == 0x75 ? "container section (TS 102 323 [13])" :
  122. t->table_id == 0x76 ? "related content section (TS 102 323 [13])" :
  123. t->table_id == 0x77 ? "content identifier section (TS 102 323 [13])" :
  124. t->table_id == 0x78 ? "MPE-FEC section (EN 301 192 [4])" :
  125. t->table_id == 0x79 ? "resolution notification section (TS 102 323 [13])" :
  126. IN(t->table_id, 0x79, 0x7d) ? "reserved for future use" :
  127. t->table_id == 0x7e ? "discontinuity_information_section" :
  128. t->table_id == 0x7f ? "section_information_section" :
  129. IN(t->table_id, 0x80, 0xfe) ? "user defined" :
  130. t->table_id == 0xff ? "reserved" : "Impossible!"
  131. );
  132. ts_LOGf(" - Section length : %03x (%d) [num_packets:%d]\n",
  133. t->section_length, t->section_length, t->num_packets);
  134. if (!t->section_syntax_indicator) {
  135. ts_LOGf(" - Private section syntax\n");
  136. } else {
  137. ts_LOGf(" - TS ID / Program No : %04x (%d)\n", t->ts_id_number, t->ts_id_number);
  138. ts_LOGf(" - Version number %d, current next %d, section number %d, last section number %d\n",
  139. t->version_number,
  140. t->current_next_indicator,
  141. t->section_number,
  142. t->last_section_number);
  143. }
  144. if (t->CRC && t->CRC != 0xffffffff)
  145. ts_LOGf(" - CRC : 0x%08x\n", t->CRC);
  146. }
  147. void ts_section_dump(struct ts_section_header *sec) {
  148. int i;
  149. ts_LOGf("%s table\n",
  150. sec->table_id == 0x00 ? "PAT" :
  151. sec->table_id == 0x01 ? "CAT" :
  152. sec->table_id == 0x02 ? "PMT" :
  153. sec->table_id == 0x03 ? "TSDT" :
  154. IN(sec->table_id, 0x40, 0x41) ? "NIT" :
  155. sec->table_id == 0x42 ? "SDT" :
  156. sec->table_id == 0x46 ? "SDT" :
  157. sec->table_id == 0x4a ? "BAT" :
  158. IN(sec->table_id, 0x4e, 0x6f) ? "EIT" :
  159. sec->table_id == 0x70 ? "TDT" :
  160. sec->table_id == 0x71 ? "RST" :
  161. sec->table_id == 0x72 ? "STUFFING" :
  162. sec->table_id == 0x73 ? "TOT" :
  163. sec->table_id == 0x7e ? "DIS" :
  164. sec->table_id == 0x7f ? "SIS" :
  165. IN(sec->table_id, 0x80, 0xfe) ? "USER_DEFINED" :
  166. sec->table_id == 0xff ? "RESERVED" : "UNKNOWN"
  167. );
  168. for (i=0;i<sec->num_packets;i++) {
  169. struct ts_header tshdr;
  170. ts_packet_header_parse(sec->packet_data + (i * TS_PACKET_SIZE), &tshdr);
  171. ts_packet_header_dump(&tshdr);
  172. }
  173. ts_section_header_dump(sec);
  174. }
  175. #undef IN