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