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.

cat.c 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. /*
  2. * CAT table parser and 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 "tsfuncs.h"
  14. struct ts_cat *ts_cat_alloc() {
  15. struct ts_cat *cat = calloc(1, sizeof(struct ts_cat));
  16. cat->section_header = ts_section_data_alloc();
  17. return cat;
  18. }
  19. void ts_cat_clear(struct ts_cat *cat) {
  20. if (!cat)
  21. return;
  22. // save
  23. struct ts_section_header *section_header = cat->section_header;
  24. // free
  25. FREE(cat->program_info);
  26. // clear
  27. ts_section_data_clear(section_header);
  28. memset(cat, 0, sizeof(struct ts_cat));
  29. // restore
  30. cat->section_header = section_header;
  31. }
  32. void ts_cat_free(struct ts_cat **pcat) {
  33. struct ts_cat *cat = *pcat;
  34. if (cat) {
  35. ts_section_data_free(&cat->section_header);
  36. FREE(cat->program_info);
  37. FREE(*pcat);
  38. }
  39. }
  40. struct ts_cat *ts_cat_push_packet(struct ts_cat *cat, uint8_t *ts_packet) {
  41. struct ts_header ts_header;
  42. memset(&ts_header, 0, sizeof(struct ts_header));
  43. if (ts_packet_header_parse(ts_packet, &ts_header)) {
  44. // Received PUSI packet before table END, clear the table to start gathering new one
  45. if (ts_header.pusi && cat->ts_header.pusi)
  46. ts_cat_clear(cat);
  47. if (!cat->ts_header.pusi)
  48. cat->ts_header = ts_header;
  49. }
  50. if (ts_header.pusi) {
  51. struct ts_section_header section_header;
  52. memset(&section_header, 0, sizeof(struct ts_section_header));
  53. uint8_t *section_data = ts_section_header_parse(ts_packet, &cat->ts_header, &section_header);
  54. if (!section_data) {
  55. memset(&cat->ts_header, 0, sizeof(struct ts_header));
  56. goto OUT;
  57. }
  58. // table_id should be 0x01 (ca_map_section)
  59. if (section_header.table_id != 0x01) {
  60. memset(&cat->ts_header, 0, sizeof(struct ts_header));
  61. goto OUT;
  62. }
  63. // Set correct section_header
  64. ts_section_header_parse(ts_packet, &cat->ts_header, cat->section_header);
  65. }
  66. if (!cat->initialized) {
  67. ts_section_add_packet(cat->section_header, &ts_header, ts_packet);
  68. if (cat->section_header->initialized) {
  69. if (!ts_cat_parse(cat))
  70. goto ERROR;
  71. }
  72. }
  73. OUT:
  74. return cat;
  75. ERROR:
  76. ts_cat_clear(cat);
  77. return cat;
  78. }
  79. int ts_cat_parse(struct ts_cat *cat) {
  80. uint8_t *section_data = cat->section_header->data;
  81. int section_len = cat->section_header->data_len;
  82. if (section_len > 4096)
  83. return 0;
  84. /* Handle streams */
  85. uint8_t *stream_data = section_data;
  86. cat->program_info_size = section_len;
  87. cat->program_info = malloc(cat->program_info_size);
  88. if (!cat->program_info)
  89. return 0;
  90. memcpy(cat->program_info, stream_data, cat->program_info_size);
  91. stream_data += cat->program_info_size;
  92. if (!ts_crc32_section_check(cat->section_header, "CAT"))
  93. return 0;
  94. cat->initialized = 1;
  95. return 1;
  96. }
  97. void ts_cat_generate(struct ts_cat *cat, uint8_t **ts_packets, int *num_packets) {
  98. uint8_t *secdata = ts_section_data_alloc_section();
  99. ts_section_header_generate(secdata, cat->section_header, 0);
  100. int curpos = 8; // Compensate for the section header, frist data byte is at offset 8
  101. memcpy(secdata + curpos, cat->program_info, cat->program_info_size);
  102. curpos += cat->program_info_size;
  103. cat->section_header->CRC = ts_section_data_calculate_crc(secdata, curpos);
  104. curpos += 4; // CRC
  105. ts_section_data_gen_ts_packets(&cat->ts_header, secdata, curpos, cat->section_header->pointer_field, ts_packets, num_packets);
  106. FREE(secdata);
  107. }
  108. void ts_cat_regenerate_packets(struct ts_cat *cat) {
  109. uint8_t *ts_packets;
  110. int num_packets;
  111. ts_cat_generate(cat, &ts_packets, &num_packets);
  112. FREE(cat->section_header->packet_data);
  113. cat->section_header->packet_data = ts_packets;
  114. cat->section_header->num_packets = num_packets;
  115. }
  116. struct ts_cat *ts_cat_copy(struct ts_cat *cat) {
  117. struct ts_cat *newcat = ts_cat_alloc();
  118. int i;
  119. for (i=0;i<cat->section_header->num_packets; i++) {
  120. newcat = ts_cat_push_packet(newcat, cat->section_header->packet_data + (i * TS_PACKET_SIZE));
  121. }
  122. if (newcat->initialized) {
  123. return newcat;
  124. } else {
  125. ts_LOGf("Error copying cat!\n");
  126. ts_cat_free(&newcat);
  127. return NULL;
  128. }
  129. }
  130. void ts_cat_check_generator(struct ts_cat *cat) {
  131. struct ts_cat *cat1 = ts_cat_copy(cat);
  132. if (cat1) {
  133. ts_compare_data("CAT (tspacket->struct)",
  134. cat1->section_header->packet_data,
  135. cat->section_header->packet_data,
  136. cat->section_header->num_packets * TS_PACKET_SIZE);
  137. ts_cat_free(&cat1);
  138. }
  139. uint8_t *ts_packets;
  140. int num_packets;
  141. ts_cat_generate(cat, &ts_packets, &num_packets);
  142. if (num_packets != cat->section_header->num_packets) {
  143. ts_LOGf("ERROR: num_packets:%d != sec->num_packets:%d\n", num_packets, cat->section_header->num_packets);
  144. }
  145. ts_compare_data("CAT (struct->tspacket)", cat->section_header->packet_data, ts_packets, num_packets * TS_PACKET_SIZE);
  146. free(ts_packets);
  147. }
  148. void ts_cat_dump(struct ts_cat *cat) {
  149. struct ts_section_header *sec = cat->section_header;
  150. ts_section_dump(sec);
  151. if (cat->program_info_size > 0) {
  152. ts_LOGf(" * Descriptor dump:\n");
  153. ts_descriptor_dump(cat->program_info, cat->program_info_size);
  154. }
  155. ts_cat_check_generator(cat);
  156. }
  157. int ts_cat_is_same(struct ts_cat *cat1, struct ts_cat *cat2) {
  158. if (cat1 == cat2) return 1; // Same
  159. if ((!cat1 && cat2) || (cat1 && !cat2)) return 0; // Not same (one is NULL)
  160. return ts_section_is_same(cat1->section_header, cat2->section_header);
  161. }
  162. enum CA_system ts_get_CA_sys(uint16_t CA_id) {
  163. if (CA_id >= 0x0100 && CA_id <= 0x01FF) return CA_SECA;
  164. if (CA_id >= 0x0500 && CA_id <= 0x05FF) return CA_VIACCESS;
  165. if (CA_id >= 0x0600 && CA_id <= 0x06FF) return CA_IRDETO;
  166. if (CA_id >= 0x0900 && CA_id <= 0x09FF) return CA_VIDEOGUARD;
  167. if (CA_id >= 0x0B00 && CA_id <= 0x0BFF) return CA_CONAX;
  168. if (CA_id >= 0x0D00 && CA_id <= 0x0DFF) return CA_CRYPTOWORKS;
  169. if (CA_id >= 0x1800 && CA_id <= 0x18FF) return CA_NAGRA;
  170. switch (CA_id) {
  171. case 0x4ABF: return CA_DGCRYPT;
  172. case 0x4AE0: return CA_DRECRYPT;
  173. case 0x4AE1: return CA_DRECRYPT;
  174. case 0x5581: return CA_BULCRYPT;
  175. case 0x4AEE: return CA_BULCRYPT;
  176. case 0x5501: return CA_GRIFFIN;
  177. case 0x5504: return CA_GRIFFIN;
  178. case 0x5506: return CA_GRIFFIN;
  179. case 0x5508: return CA_GRIFFIN;
  180. case 0x5509: return CA_GRIFFIN;
  181. case 0x550E: return CA_GRIFFIN;
  182. case 0x5511: return CA_GRIFFIN;
  183. }
  184. return CA_UNKNOWN;
  185. }
  186. char * ts_get_CA_sys_txt(enum CA_system CA_sys) {
  187. switch (CA_sys) {
  188. case CA_SECA: return "SECA";
  189. case CA_VIACCESS: return "VIACCESS";
  190. case CA_IRDETO: return "IRDETO";
  191. case CA_VIDEOGUARD: return "VIDEOGUARD";
  192. case CA_CONAX: return "CONAX";
  193. case CA_CRYPTOWORKS: return "CRYPTOWORKS";
  194. case CA_NAGRA: return "NAGRA";
  195. case CA_DRECRYPT: return "DRE-CRYPT";
  196. case CA_BULCRYPT: return "BULCRYPT";
  197. case CA_GRIFFIN: return "GRIFFIN";
  198. case CA_DGCRYPT: return "DGCRYPT";
  199. case CA_UNKNOWN: return "UNKNOWN";
  200. }
  201. return "UNKNOWN";
  202. }
  203. static int find_CA_descriptor(uint8_t *data, int data_len, enum CA_system req_CA_type, uint16_t *CA_id, uint16_t *CA_pid) {
  204. while (data_len >= 2) {
  205. uint8_t tag = data[0];
  206. uint8_t this_length = data[1];
  207. data += 2;
  208. data_len -= 2;
  209. if (tag == 9 && this_length >= 4) {
  210. uint16_t CA_ID = (data[0] << 8) | data[1];
  211. uint16_t CA_PID = ((data[2] & 0x1F) << 8) | data[3];
  212. if (ts_get_CA_sys(CA_ID) == req_CA_type) {
  213. *CA_id = CA_ID;
  214. *CA_pid = CA_PID;
  215. return 1;
  216. }
  217. }
  218. data_len -= this_length;
  219. data += this_length;
  220. }
  221. return 0;
  222. }
  223. int ts_get_emm_info(struct ts_cat *cat, enum CA_system req_CA_type, uint16_t *CA_id, uint16_t *CA_pid) {
  224. return find_CA_descriptor(cat->program_info, cat->program_info_size, req_CA_type, CA_id, CA_pid);
  225. }
  226. int ts_get_ecm_info(struct ts_pmt *pmt, enum CA_system req_CA_type, uint16_t *CA_id, uint16_t *CA_pid) {
  227. int i, result = find_CA_descriptor(pmt->program_info, pmt->program_info_size, req_CA_type, CA_id, CA_pid);
  228. if (!result) {
  229. for(i=0;i<pmt->streams_num;i++) {
  230. struct ts_pmt_stream *stream = pmt->streams[i];
  231. if (stream->ES_info) {
  232. result = find_CA_descriptor(stream->ES_info, stream->ES_info_size, req_CA_type, CA_id, CA_pid);
  233. if (result)
  234. break;
  235. }
  236. }
  237. }
  238. return result;
  239. }
  240. static int find_CA_descriptor_by_caid(uint8_t *data, int data_len, uint16_t caid, uint16_t *CA_pid) {
  241. while (data_len >= 2) {
  242. uint8_t tag = data[0];
  243. uint8_t this_length = data[1];
  244. data += 2;
  245. data_len -= 2;
  246. if (tag == 9 && this_length >= 4) {
  247. uint16_t CA_ID = (data[0] << 8) | data[1];
  248. uint16_t CA_PID = ((data[2] & 0x1F) << 8) | data[3];
  249. if (CA_ID == caid) {
  250. *CA_pid = CA_PID;
  251. return 1;
  252. }
  253. }
  254. data_len -= this_length;
  255. data += this_length;
  256. }
  257. return 0;
  258. }
  259. int ts_get_emm_info_by_caid(struct ts_cat *cat, uint16_t caid, uint16_t *ca_pid) {
  260. return find_CA_descriptor_by_caid(cat->program_info, cat->program_info_size, caid, ca_pid);
  261. }
  262. int ts_get_ecm_info_by_caid(struct ts_pmt *pmt, uint16_t caid, uint16_t *ca_pid) {
  263. int i, result = find_CA_descriptor_by_caid(pmt->program_info, pmt->program_info_size, caid, ca_pid);
  264. if (!result) {
  265. for(i=0;i<pmt->streams_num;i++) {
  266. struct ts_pmt_stream *stream = pmt->streams[i];
  267. if (stream->ES_info) {
  268. result = find_CA_descriptor_by_caid(stream->ES_info, stream->ES_info_size, caid, ca_pid);
  269. if (result)
  270. break;
  271. }
  272. }
  273. }
  274. return result;
  275. }
  276. static int find_CA_descriptor_by_pid(uint8_t *data, int data_len, uint16_t *caid, uint16_t pid) {
  277. while (data_len >= 2) {
  278. uint8_t tag = data[0];
  279. uint8_t this_length = data[1];
  280. data += 2;
  281. data_len -= 2;
  282. if (tag == 9 && this_length >= 4) {
  283. uint16_t CA_ID = (data[0] << 8) | data[1];
  284. uint16_t CA_PID = ((data[2] & 0x1F) << 8) | data[3];
  285. if (CA_PID == pid) {
  286. *caid = CA_ID;
  287. return 1;
  288. }
  289. }
  290. data_len -= this_length;
  291. data += this_length;
  292. }
  293. return 0;
  294. }
  295. int ts_get_emm_info_by_pid(struct ts_cat *cat, uint16_t *caid, uint16_t ca_pid) {
  296. return find_CA_descriptor_by_pid(cat->program_info, cat->program_info_size, caid, ca_pid);
  297. }
  298. int ts_get_ecm_info_by_pid(struct ts_pmt *pmt, uint16_t *caid, uint16_t ca_pid) {
  299. int i, result = find_CA_descriptor_by_pid(pmt->program_info, pmt->program_info_size, caid, ca_pid);
  300. if (!result) {
  301. for(i=0;i<pmt->streams_num;i++) {
  302. struct ts_pmt_stream *stream = pmt->streams[i];
  303. if (stream->ES_info) {
  304. result = find_CA_descriptor_by_pid(stream->ES_info, stream->ES_info_size, caid, ca_pid);
  305. if (result)
  306. break;
  307. }
  308. }
  309. }
  310. return result;
  311. }