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

pes_es.c 4.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. #include <netdb.h>
  2. #include <string.h>
  3. #include "tsfuncs.h"
  4. int ts_pes_es_mpeg_audio_header_parse(struct mpeg_audio_header *mpghdr, uint8_t *data, int datasz) {
  5. if (datasz < 4)
  6. return 0;
  7. uint8_t d1 = data[0];
  8. uint8_t d2 = data[1];
  9. uint8_t d3 = data[2];
  10. uint8_t d4 = data[3];
  11. mpghdr->syncword = (int)d1 << 4 | (d2 >> 4); // 12 bits
  12. mpghdr->ID = bit_on(d2, bit_4); // 1 bit
  13. mpghdr->layer = (d2 &~ 0xf9) >> 1; // 2 bits
  14. mpghdr->protection_bit = bit_on(d2, bit_1); // 1 bit
  15. mpghdr->bitrate_index = d3 >> 4; // 4 bits
  16. mpghdr->sampl_freq = (d3 &~ 0xf3) >> 2; // 2 bits
  17. mpghdr->padding_bit = bit_on(d3, bit_2); // 1 bit
  18. mpghdr->private_bit = bit_on(d3, bit_1); // 1 bit
  19. mpghdr->mode = d4 >> 6; // 2 bits
  20. mpghdr->mode_extension = (d4 &~ 0xcf) >> 4; // 2 bits
  21. mpghdr->copyright = bit_on(d4, bit_4); // 1 bit
  22. mpghdr->org_home = bit_on(d4, bit_3); // 1 bit
  23. mpghdr->emphasis = d4 &~ 0xfc; // 2 bits
  24. if (mpghdr->syncword != 0xfff) {
  25. ts_LOGf("!!! Error parsing mpeg audio header! Syncword should be 0xfff but it is 0x%03x!\n", mpghdr->syncword);
  26. return 0;
  27. } else {
  28. mpghdr->initialized = 1;
  29. return 1;
  30. }
  31. }
  32. void ts_pes_es_mpeg_audio_header_dump(struct mpeg_audio_header *mpghdr) {
  33. if (!mpghdr->initialized)
  34. return;
  35. // See ISO-11172-3 for more info
  36. ts_LOGf(" - ES analyze audio frame\n");
  37. ts_LOGf(" - Syncword : %x\n", mpghdr->syncword);
  38. if (mpghdr->syncword != 0xfff) {
  39. ts_LOGf("!!! ERROR: MPEG audo Syncword should be 0xfff!\n");
  40. return;
  41. }
  42. ts_LOGf(" - ID : %d (%s)\n", mpghdr->ID, mpghdr->ID ? "MPEG Audio" : "Other");
  43. ts_LOGf(" - layer : %d (%s)\n", mpghdr->layer,
  44. mpghdr->layer == 0 ? "reserved" :
  45. mpghdr->layer == 1 ? "Layer III" :
  46. mpghdr->layer == 2 ? "Layer II" :
  47. mpghdr->layer == 3 ? "Layer I" : "reserved"
  48. );
  49. ts_LOGf(" - protection_bit: %x\n", mpghdr->protection_bit);
  50. int br = 0;
  51. if (mpghdr->layer > 0 && mpghdr->layer < 4) {
  52. int bitrate_index_table[4][16] = {
  53. [3] = { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, -1}, // Layer 1
  54. [2] = { 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, -1}, // Layer 2
  55. [1] = { 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, -1} // Layer 3
  56. };
  57. br = bitrate_index_table[mpghdr->layer][mpghdr->bitrate_index];
  58. }
  59. ts_LOGf(" - bitrate_index : %d (%d kBit/s)\n", mpghdr->bitrate_index, br);
  60. ts_LOGf(" - sampl_freq : %d (%s)\n", mpghdr->sampl_freq,
  61. mpghdr->sampl_freq == 0 ? "44.1 kHz" :
  62. mpghdr->sampl_freq == 1 ? "48 kHz" :
  63. mpghdr->sampl_freq == 2 ? "32 kHz" : "reserved"
  64. );
  65. ts_LOGf(" - padding_bit : %d\n", mpghdr->padding_bit);
  66. ts_LOGf(" - private_bit : %d\n", mpghdr->private_bit);
  67. ts_LOGf(" - mode : %d (%s)\n", mpghdr->mode,
  68. mpghdr->mode == 0 ? "stereo" :
  69. mpghdr->mode == 1 ? "join_stereo" :
  70. mpghdr->mode == 2 ? "dual_channel" : "single_channel"
  71. );
  72. ts_LOGf(" - mode_extension: %x\n", mpghdr->mode_extension);
  73. ts_LOGf(" - copyright : %x\n", mpghdr->copyright);
  74. ts_LOGf(" - org_home : %x\n", mpghdr->org_home);
  75. ts_LOGf(" - emphasis : %d (%s)\n", mpghdr->emphasis,
  76. mpghdr->emphasis == 0 ? "none" :
  77. mpghdr->emphasis == 1 ? "50/15 microseconds" :
  78. mpghdr->emphasis == 2 ? "reserved" : "CCITT J.17"
  79. );
  80. }
  81. void ts_pes_es_parse(struct ts_pes *pes) {
  82. if (!pes->es_data)
  83. return;
  84. // Parse MPEG audio packet header
  85. if ((pes->is_audio_mpeg1 || pes->is_audio_mpeg2) && pes->es_data_size > 4) {
  86. struct mpeg_audio_header mpghdr;
  87. memset(&mpghdr, 0, sizeof(struct mpeg_audio_header));
  88. ts_pes_es_mpeg_audio_header_parse(&mpghdr, pes->es_data, pes->es_data_size);
  89. if (mpghdr.initialized) {
  90. pes->mpeg_audio_header = mpghdr;
  91. if (mpghdr.ID) {
  92. switch (mpghdr.layer) {
  93. case 3: pes->is_audio_mpeg1l1 = 1; break;
  94. case 2: pes->is_audio_mpeg1l2 = 1; break;
  95. case 1: pes->is_audio_mpeg1l3 = 1; break;
  96. }
  97. }
  98. }
  99. }
  100. // Look into elementary streams to detect AC3/DTS
  101. if (pes->is_audio_ac3) {
  102. if (pes->real_pes_packet_len >= 2 && (pes->es_data[0] == 0x0B && pes->es_data[1] == 0x77)) {
  103. pes->is_audio = 1;
  104. pes->is_audio_ac3 = 1;
  105. pes->is_audio_dts = 0;
  106. }
  107. if (pes->real_pes_packet_len >= 4 && (pes->es_data[0] == 0x7f && pes->es_data[1] == 0xfe && pes->es_data[2] == 0x80 && pes->es_data[3] == 0x01)) {
  108. pes->is_audio = 1;
  109. pes->is_audio_ac3 = 0;
  110. pes->is_audio_dts = 1;
  111. }
  112. }
  113. }
  114. void ts_pes_es_dump(struct ts_pes *pes) {
  115. if (pes->is_audio && pes->mpeg_audio_header.initialized) {
  116. ts_pes_es_mpeg_audio_header_dump(&pes->mpeg_audio_header);
  117. }
  118. }