Skip to content

Commit a6378a8

Browse files
committed
CodecMTS update parsePES
1 parent 96b5e27 commit a6378a8

File tree

3 files changed

+237
-115
lines changed

3 files changed

+237
-115
lines changed

src/AudioTools/AudioCodecs/CodecMTS.h

Lines changed: 151 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,13 @@ enum class MTSStreamType {
6464
ATSC_USER_PRIV = 0xEB,
6565
};
6666

67+
// enum class AACProfile : uint8_t {
68+
// MAIN = 0, // AAC Main (High complexity, rarely used)
69+
// LC = 1, // AAC Low Complexity (Most common)
70+
// SSR = 2, // AAC Scalable Sample Rate (Rare)
71+
// LTP = 3 // AAC Long Term Prediction (Not widely supported)
72+
// };
73+
6774
/**
6875
* @brief MPEG-TS (MTS) decoder. Extracts (demuxes) the AAC audio data from a
6976
*MPEG-TS (MTS) data stream. You can define the relevant stream types via the
@@ -159,6 +166,9 @@ class MTSDecoder : public AudioDecoder {
159166
Vector<int> pids{0};
160167
AudioDecoder *p_dec = nullptr;
161168
uint16_t pmt_pid = 0xFFFF;
169+
//AACProfile aac_profile = AACProfile::LC;
170+
MTSStreamType selected_stream_type;
171+
int open_pes_data_size = 0;
162172

163173
/// Add the PID for which we want to extract the audio data from the PES
164174
/// packets
@@ -212,9 +222,13 @@ class MTSDecoder : public AudioDecoder {
212222
int pid = ((packet[1] & 0x1F) << 8) | (packet[2] & 0xFF);
213223
LOGI("PID: 0x%04X(%d)", pid, pid);
214224
int payloadUnitStartIndicator = (packet[1] & 0x40) >> 6;
215-
LOGI("Payload Unit Start Indicator: %d", payloadUnitStartIndicator);
225+
LOGI("Payload Unit Start Indicator (PUSI): %d", payloadUnitStartIndicator);
216226
int adaptionFieldControl = (packet[3] & 0x30) == 0x20;
217-
LOGI("Adaption Field Control: %d", adaptionFieldControl);
227+
int adaptationSize = 0;
228+
if (adaptionFieldControl) {
229+
adaptationSize = packet[4];
230+
}
231+
LOGI("Adaption Field Control: 0x%x / size: %d", adaptionFieldControl, adaptationSize);
218232

219233
bool has_payload = true;
220234
if ((packet[3] & 0x10) >> 4 == 0) {
@@ -247,7 +261,7 @@ class MTSDecoder : public AudioDecoder {
247261
parsePMT(&packet[payloadStart], len);
248262
} else if (pids.contains(pid)) {
249263
parsePES(&packet[payloadStart], payloadUnitStartIndicator ? true : false,
250-
len);
264+
len, adaptationSize);
251265
} else {
252266
LOGE("-> Packet ignored for %d", pid);
253267
}
@@ -279,62 +293,161 @@ class MTSDecoder : public AudioDecoder {
279293
LOGI("Using PMT PID: 0x%04X(%d)", pmt_pid, pmt_pid);
280294
}
281295

282-
void parsePMT(uint8_t *pat, int len) {
296+
void parsePMT(uint8_t *pmt, int len) {
283297
TRACEI();
284-
assert(pat[0] == 0x02); // Program Association section
298+
assert(pmt[0] == 0x02); // Program Association section
285299
int staticLengthOfPMT = 12;
286-
int sectionLength = ((pat[1] & 0x0F) << 8) | (pat[2] & 0xFF);
287-
LOGI("PMT Section Length: %d", sectionLength);
288-
int programInfoLength = ((pat[10] & 0x0F) << 8) | (pat[11] & 0xFF);
289-
LOGI("PMT Program Info Length: %d", programInfoLength);
300+
int sectionLength = ((pmt[1] & 0x0F) << 8) | (pmt[2] & 0xFF);
301+
LOGI("- PMT Section Length: %d", sectionLength);
302+
int programInfoLength = ((pmt[10] & 0x0F) << 8) | (pmt[11] & 0xFF);
303+
LOGI("- PMT Program Info Length: %d", programInfoLength);
290304

291305
int cursor = staticLengthOfPMT + programInfoLength;
292306
while (cursor < sectionLength - 1) {
293-
int streamType = pat[cursor] & 0xFF;
307+
MTSStreamType streamType = static_cast<MTSStreamType>(pmt[cursor] & 0xFF);
294308
int elementaryPID =
295-
((pat[cursor + 1] & 0x1F) << 8) | (pat[cursor + 2] & 0xFF);
296-
LOGI("Stream Type: 0x%02X(%d) Elementary PID: 0x%04X(%d)", streamType,
297-
streamType, elementaryPID, elementaryPID);
309+
((pmt[cursor + 1] & 0x1F) << 8) | (pmt[cursor + 2] & 0xFF);
310+
LOGI("-- Stream Type: 0x%02X(%d) [%s] for Elementary PID: 0x%04X(%d)",
311+
streamType, streamType, toStr(streamType), elementaryPID,
312+
elementaryPID);
298313

299-
if (isStreamTypeActive((MTSStreamType)streamType)) {
314+
if (isStreamTypeActive(streamType)) {
315+
selected_stream_type = streamType;
300316
addPID(elementaryPID);
301317
}
302318

303319
int esInfoLength =
304-
((pat[cursor + 3] & 0x0F) << 8) | (pat[cursor + 4] & 0xFF);
305-
LOGI("ES Info Length: 0x%04X(%d)", esInfoLength, esInfoLength);
320+
((pmt[cursor + 3] & 0x0F) << 8) | (pmt[cursor + 4] & 0xFF);
321+
LOGI("-- ES Info Length: 0x%04X(%d)", esInfoLength, esInfoLength);
306322
cursor += 5 + esInfoLength;
307323
}
308324
}
309325

310-
void parsePES(uint8_t *pat, const bool isNewPayload, int len) {
326+
void parsePES(uint8_t *pes, const bool isNewPayload, int len,
327+
int adaptationSize) {
311328
TRACEI();
329+
uint8_t *data = nullptr;
312330
int dataSize = 0;
331+
313332
if (isNewPayload) {
314-
uint8_t streamID = pat[3] & 0xFF;
315-
LOGI("Stream ID:%02X ", streamID);
316-
const uint8_t posOfPacketLengthLatterHalf = 5;
317-
int pesRemainingPacketLength = ((pat[4] & 0xFF) << 8) | (pat[5] & 0xFF);
318-
LOGI("PES Packet length: %d", pesRemainingPacketLength);
319-
// pesDataLength = pesRemainingPacketLength;
320-
const uint8_t posOfHeaderLength = 8;
321-
uint8_t pesRemainingHeaderLength = pat[posOfHeaderLength] & 0xFF;
322-
LOGI("PES Header length: %d", pesRemainingHeaderLength);
323-
int startOfData = pesRemainingHeaderLength;
324-
dataSize = len - startOfData;
325-
LOGI("PES Data size: %d", dataSize);
326-
if (dataSize < 0) dataSize = 0;
327-
if (p_print) p_print->write(&pat[startOfData], dataSize);
328-
if (p_dec) p_dec->write(&pat[startOfData], dataSize);
329-
// pesDataLength -= len - (posOfPacketLengthLatterHalf + 1);
333+
// check for PES packet start code prefix
334+
assert(pes[0] == 0);
335+
assert(pes[1] == 0);
336+
assert(pes[3] == 0x1);
337+
assert(len >= 6);
338+
339+
int pesPacketLength = (static_cast<int>(pes[4]) << 8) | static_cast<int>(pes[5]);
340+
341+
// PES Header size is at least 6 bytes, but can be larger with optional
342+
// fields
343+
int pesHeaderSize = 6;
344+
if ((pes[6] & 0xC0) != 0) { // Check for PTS/DTS flags
345+
pesHeaderSize += 3 + ((pes[7] & 0xC0) == 0xC0 ? 5 : 0);
346+
pesHeaderSize += pes[8]; // PES header stuffing size
347+
}
348+
LOGI("- PES Header Size: %d", pesHeaderSize);
349+
350+
assert(pesHeaderSize < len);
351+
352+
data = pes + pesHeaderSize;
353+
dataSize = len - pesHeaderSize;
354+
assert(dataSize > 0);
355+
356+
open_pes_data_size = pesPacketLength;
357+
330358
} else {
331-
dataSize = len;
332-
LOGI("PES Data size: %d", dataSize);
333-
if (p_print) p_print->write(pat, dataSize);
334-
if (p_dec) p_dec->write(pat, dataSize);
335-
// pesDataLength -= dataSize;
359+
data = pes + adaptationSize;
360+
dataSize = len - adaptationSize;
336361
}
362+
open_pes_data_size -= dataSize;
363+
364+
LOGI("- writing %d bytes (open: %d)", dataSize, open_pes_data_size);
365+
366+
if (p_print) p_print->write(data, dataSize);
367+
if (p_dec) p_dec->write(data, dataSize);
337368
}
369+
370+
const char *toStr(MTSStreamType type) {
371+
switch (type) {
372+
case MTSStreamType::AUDIO_MP3:
373+
return "AUDIO_MP3";
374+
case MTSStreamType::AUDIO_MP3_LOW_BITRATE:
375+
return "AUDIO_MP3_LOW_BITRATE";
376+
case MTSStreamType::AUDIO_AAC:
377+
return "AUDIO_AAC";
378+
case MTSStreamType::AUDIO_AAC_LATM:
379+
return "AUDIO_AAC_LATM";
380+
default:
381+
return "UNKNOWN";
382+
}
383+
}
384+
385+
// // Sampling Frequency Index Lookup
386+
// uint8_t getSamplingFrequencyIndex(uint32_t sample_rate) {
387+
// switch (sample_rate) {
388+
// case 96000:
389+
// return 0;
390+
// case 88200:
391+
// return 1;
392+
// case 64000:
393+
// return 2;
394+
// case 48000:
395+
// return 3;
396+
// case 44100:
397+
// return 4;
398+
// case 32000:
399+
// return 5;
400+
// case 24000:
401+
// return 6;
402+
// case 22050:
403+
// return 7;
404+
// case 16000:
405+
// return 8;
406+
// case 12000:
407+
// return 9;
408+
// case 11025:
409+
// return 10;
410+
// case 8000:
411+
// return 11;
412+
// case 7350:
413+
// return 12;
414+
// default:
415+
// return 4; // Default to 44.1kHz
416+
// }
417+
// }
418+
419+
// // Function to add ADTS header to raw AAC data
420+
// void writeADTSHeader(size_t frame_length) {
421+
// LOGI("writeADTSHeader: %d", (int)frame_length);
422+
// AudioInfo info = audioInfo();
423+
// uint8_t profile = 1; // AAC-LC (Low Complexity)
424+
// uint8_t sample_index = getSamplingFrequencyIndex(info.sample_rate);
425+
426+
// uint8_t adts_header[7] = {0};
427+
428+
// // ADTS Header (7 bytes)
429+
// adts_header[0] = 0xFF; // Syncword (first byte)
430+
// adts_header[1] = 0xF1; // Syncword (second byte) + MPEG Version + Layer
431+
// adts_header[2] =
432+
// ((profile - 1) << 6) | (sample_index << 2) | (info.channels >> 2);
433+
// adts_header[3] = ((info.channels & 3) << 6) | ((frame_length >> 11) & 0x03);
434+
// adts_header[4] = (frame_length >> 3) & 0xFF;
435+
// adts_header[5] = ((frame_length & 0x07) << 5) | 0x1F;
436+
// adts_header[6] = 0xFC; // Buffer fullness (0x7FF), 1 AAC frame per ADTS
437+
438+
// if (p_print) p_print->write(adts_header, sizeof(adts_header));
439+
// if (p_dec) p_print->write(adts_header, sizeof(adts_header));
440+
// }
441+
442+
/// Finds the mp3/aac sync word
443+
// int findSyncWord(const uint8_t *buf, size_t nBytes, uint8_t synch = 0xFF,
444+
// uint8_t syncl = 0xF0) {
445+
// for (int i = 0; i < nBytes - 1; i++) {
446+
// if ((buf[i + 0] & synch) == synch && (buf[i + 1] & syncl) == syncl)
447+
// return i;
448+
// }
449+
// return -1;
450+
// }
338451
};
339452

340453
using MPEG_TSDecoder = MTSDecoder;

0 commit comments

Comments
 (0)