@@ -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
340453using MPEG_TSDecoder = MTSDecoder;
0 commit comments