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

misc.c 6.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <netdb.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <ctype.h>
  7. #include "tsfuncs.h"
  8. int dec2bcd(int dec) {
  9. return ((dec/10) << 4) + dec % 10;
  10. }
  11. int bcd2dec(int bcd) {
  12. return ((bcd>>4) * 10) + bcd % 16;
  13. }
  14. void ts_hex_dump_buf(char *buf, int bufsz, uint8_t *d, int size, int col) {
  15. int i;
  16. if (bufsz < size * 6)
  17. return;
  18. memset(buf, 0, bufsz);
  19. for (i=0;i<size;i++) {
  20. if (col && (i % col == col - 1))
  21. sprintf(buf+(i*3), "%02x\n", d[i]);
  22. else
  23. sprintf(buf+(i*3), "%02x ", d[i]);
  24. }
  25. }
  26. char *ts_hex_dump(uint8_t *d, int size, int col) {
  27. char *buf = malloc(size * 6);
  28. if (!buf)
  29. return NULL;
  30. ts_hex_dump_buf(buf, size * 6, d, size, col);
  31. return buf;
  32. }
  33. void ts_print_bytes(char *prefix, uint8_t *d, int size) {
  34. char *buf = ts_hex_dump(d, size, 0);
  35. ts_LOGf("%s -> %s\n", prefix, buf);
  36. free(buf);
  37. }
  38. void ts_compare_data(char *prefix, uint8_t *a, uint8_t *b, int size) {
  39. if (!a) {
  40. ts_LOGf("%s: !a\n", prefix);
  41. return;
  42. }
  43. if (!b) {
  44. ts_LOGf("%s: !b\n", prefix);
  45. return;
  46. }
  47. if (memcmp(a, b, size) == 0) {
  48. ts_LOGf(" **** %s generator is correct ****\n", prefix);
  49. } else {
  50. int i;
  51. for (i=0;i<size;i++) {
  52. ts_LOGf("%03d - %02x %02x | %s\n", i, a[i], b[i], a[i] == b[i] ? "ok" : "err");
  53. }
  54. }
  55. }
  56. char *init_dvb_string(uint8_t encoding, char *text) {
  57. if (!text)
  58. return NULL;
  59. int len = strlen(text);
  60. if (!len)
  61. return NULL;
  62. char *dvbtext = calloc(1, len + 2);
  63. memcpy(dvbtext + 1, text, len);
  64. dvbtext[0] = encoding; // See EN 300 469 table A.3
  65. return dvbtext;
  66. }
  67. char *init_dvb_string_utf8(char *text) {
  68. return init_dvb_string(0x10, text);
  69. }
  70. char *init_dvb_string_iso_8859_5(char *text) {
  71. return init_dvb_string(0x01, text);
  72. }
  73. int ts_is_psi_pid(uint16_t pid, struct ts_pat *pat) {
  74. // Skip PAT && reserved, SDT, EIT, RST, TDT/TOT. They are PSI packets
  75. if (pid < 0x10 || pid == 0x11 || pid == 0x12 || pid == 0x13 || pid == 0x14)
  76. return 1;
  77. int i;
  78. for (i=0;i<pat->programs_num;i++) {
  79. struct ts_pat_program *prg = pat->programs[i];
  80. if (prg->pid == pid) // PMT's are PSI
  81. return 1;
  82. }
  83. return 0;
  84. }
  85. int ts_is_stream_type_video(uint8_t stream_type) {
  86. return stream_type == STREAM_TYPE_MPEG1_VIDEO ||
  87. stream_type == STREAM_TYPE_MPEG2_VIDEO ||
  88. stream_type == STREAM_TYPE_AVC_VIDEO ||
  89. stream_type == STREAM_TYPE_AVS_VIDEO ||
  90. stream_type == STREAM_TYPE_MPEG4_PART2_VIDEO;
  91. }
  92. // This is not enough! Must look at stream descriptors to be sure!!!
  93. int ts_is_stream_type_ac3(uint8_t stream_type) {
  94. return stream_type == STREAM_TYPE_DOLBY_DVB_AUDIO ||
  95. stream_type == STREAM_TYPE_DOLBY_ATSC_AUDIO;
  96. }
  97. int ts_is_stream_type_audio(uint8_t stream_type) {
  98. return stream_type == STREAM_TYPE_MPEG1_AUDIO ||
  99. stream_type == STREAM_TYPE_MPEG2_AUDIO ||
  100. stream_type == STREAM_TYPE_ADTS_AUDIO ||
  101. ts_is_stream_type_ac3(stream_type);
  102. }
  103. // ISO/IEC 13818-1 : 2000 (E) | Table 2-29 - Stream type assignments, Page 66 (48)
  104. char *h222_stream_type_desc(uint8_t stream_type) {
  105. if (stream_type == 0 || (stream_type > 0x1c && stream_type < 0x7e))
  106. return "Reserved";
  107. switch (stream_type) {
  108. case 0x01: return "11172-2 video (MPEG-1)";
  109. case 0x02: return "H.262/13818-2 video (MPEG-2) or 11172-2 constrained video";
  110. case 0x03: return "11172-3 audio (MPEG-1)";
  111. case 0x04: return "13818-3 audio (MPEG-2)";
  112. case 0x05: return "H.222.0/13818-1 private sections";
  113. case 0x06: return "H.222.0/13818-1 PES private data";
  114. case 0x07: return "13522 MHEG";
  115. case 0x08: return "H.222.0/13818-1 Annex A - DSM CC";
  116. case 0x09: return "H.222.1";
  117. case 0x0A: return "13818-6 type A";
  118. case 0x0B: return "13818-6 type B";
  119. case 0x0C: return "13818-6 type C";
  120. case 0x0D: return "13818-6 type D";
  121. case 0x0E: return "H.222.0/13818-1 auxiliary";
  122. case 0x0F: return "13818-7 Audio with ADTS transport syntax";
  123. case 0x10: return "14496-2 Visual (MPEG-4 part 2 video)";
  124. case 0x11: return "14496-3 Audio with LATM transport syntax (14496-3/AMD 1)";
  125. case 0x12: return "14496-1 SL-packetized or FlexMux stream in PES packets";
  126. case 0x13: return "14496-1 SL-packetized or FlexMux stream in 14496 sections";
  127. case 0x14: return "ISO/IEC 13818-6 Synchronized Download Protocol";
  128. case 0x15: return "Metadata in PES packets";
  129. case 0x16: return "Metadata in metadata_sections";
  130. case 0x17: return "Metadata in 13818-6 Data Carousel";
  131. case 0x18: return "Metadata in 13818-6 Object Carousel";
  132. case 0x19: return "Metadata in 13818-6 Synchronized Download Protocol";
  133. case 0x1A: return "13818-11 MPEG-2 IPMP stream";
  134. case 0x1B: return "H.264/14496-10 video (MPEG-4/AVC)";
  135. case 0x42: return "AVS Video";
  136. case 0x7F: return "IPMP stream";
  137. default : return "Unknown";
  138. }
  139. }
  140. // System start codes, ISO 13818-1, Table 2-18
  141. // The function allocates memory which should be freed by the caller
  142. char *h222_stream_id_desc(uint8_t stream_id) {
  143. uint8_t stream_number;
  144. char *text = NULL;
  145. switch (stream_id) {
  146. case 0xbc: return strdup("Program stream map"); break;
  147. case 0xbd: return strdup("Private stream 1"); break;
  148. case 0xbe: return strdup("Padding stream"); break;
  149. case 0xbf: return strdup("Private stream 2"); break;
  150. case 0xf0: return strdup("ECM stream"); break;
  151. case 0xf1: return strdup("EMM stream"); break;
  152. case 0xf2: return strdup("DSMCC stream"); break;
  153. case 0xf3: return strdup("13522 stream"); break;
  154. case 0xf4: return strdup("H.222 A stream"); break;
  155. case 0xf5: return strdup("H.222 B stream"); break;
  156. case 0xf6: return strdup("H.222 C stream"); break;
  157. case 0xf7: return strdup("H.222 D stream"); break;
  158. case 0xf8: return strdup("H.222 E stream"); break;
  159. case 0xf9: return strdup("Ancillary stream"); break;
  160. case 0xff: return strdup("Program stream directory"); break;
  161. }
  162. if (stream_id >= 0xc0 && stream_id <= 0xdf) {
  163. stream_number = stream_id & 0x1f;
  164. asprintf(&text, "Audio stream %d", stream_number);
  165. } else if (stream_id >= 0xe0 && stream_id <= 0xef) {
  166. stream_number = stream_id & 0x0f;
  167. asprintf(&text, "Video stream %d", stream_number);
  168. } else if (stream_id >= 0xfc && stream_id <= 0xfe) {
  169. asprintf(&text, "Reserved data stream");
  170. } else {
  171. asprintf(&text, "Unrecognised stream id 0x%02x", stream_id);
  172. }
  173. return text;
  174. }
  175. void pidmap_clear(pidmap_t *pm) {
  176. memset(pm, 0, sizeof(pidmap_t));
  177. }
  178. void pidmap_set(pidmap_t *pm, uint16_t pid) {
  179. if (pid < sizeof(pidmap_t))
  180. (*pm)[pid] = 1;
  181. }
  182. void pidmap_set_val(pidmap_t *pm, uint16_t pid, uint8_t val) {
  183. if (pid < sizeof(pidmap_t))
  184. (*pm)[pid] = val;
  185. }
  186. int pidmap_get(pidmap_t *pm, uint16_t pid) {
  187. if (pid < sizeof(pidmap_t))
  188. return (*pm)[pid];
  189. return 0;
  190. }