3#define TS_PACKET_SIZE 188
5#ifndef MTS_WRITE_BUFFER_SIZE
6#define MTS_WRITE_BUFFER_SIZE 2000
9#include "AudioTools/AudioCodecs/AudioCodecsBase.h"
10#include "AudioTools/CoreAudio/AudioTypes.h"
11#include "AudioToolsConfig.h"
24 AUDIO_MP3_LOW_BITRATE = 0x04,
37 AUDIO_AAC_LATM = 0x11,
42 METDATA_SECTIONS = 0x16,
43 METADATA_DATA_CAROUSEL = 0x17,
44 METADATA_OBJ_CAROUSEL = 0x18,
45 METADATA_SYNC_DOWNLOAD = 0x19,
51 SCTE_STD_SUBTITLE = 0x82,
52 SCTE_ISOCH_DATA = 0x83,
60 ATSC_DATA_SERVICE_TABLE = 0x95,
63 ATSC_SYNC_DATA = 0xC2,
64 SCTE_AYSNC_DATA = 0xC3,
65 ATSC_USER_PRIV_PROG_ELEMENTS = 0xC4,
67 ATSC_USER_PRIV = 0xEB,
100 is_adts_missing =
false;
101 open_pes_data_size = 0;
105 if (stream_types.empty()) {
115 if (p_dec) p_dec->begin();
123 if (p_dec) p_dec->end();
127 virtual operator bool()
override {
return is_active; }
130 const char *
mime() {
return "video/MP2T"; }
132 size_t write(
const uint8_t *data,
size_t len)
override {
141 LOGI(
"MTSDecoder::write: Buffer full");
145 LOGI(
"MTSDecoder::write: %d", (
int)len);
146 size_t result = buffer.
writeArray((uint8_t *)data, len);
157 stream_types.clear();
163 stream_types.push_back(type);
168 for (
int j = 0; j < stream_types.size(); j++) {
169 if (stream_types[j] == type)
return true;
202 bool is_active =
false;
204 Vector<MTSStreamType> stream_types;
206 AudioDecoder *p_dec =
nullptr;
207 uint16_t pmt_pid = 0xFFFF;
210 int open_pes_data_size = 0;
211 int frame_length = 0;
212 bool is_adts_missing =
false;
213 size_t pes_count = 0;
218 if (pid == 0)
return;
219 for (
int j = 0; j < pids.size(); j++) {
220 if (pids[j] == pid)
return;
222 LOGI(
"-> PMT PID: 0x%04X(%d)", pid, pid);
231 LOGI(
"demux: step #%d with PES #%d", ++count, (
int)pes_count);
233 LOGI(
"Number of demux calls: %d", count);
239 if (len < TS_PACKET_SIZE)
return -1;
240 for (
int j = 0; j < len; j++) {
241 if (buffer.
data()[j] == 0x47) {
251 if (pos < 0)
return false;
253 LOGW(
"Sync byte not found at position 0. Skipping %d bytes", pos);
257 uint8_t *packet = buffer.
data();
258 int pid = ((packet[1] & 0x1F) << 8) | (packet[2] & 0xFF);
259 LOGI(
"PID: 0x%04X(%d)", pid, pid);
262 if (!is_adts_missing && pids.contains(pid)) {
276 bool payloadUnitStartIndicator =
false;
279 getPayloadStart(packet,
false, payloadUnitStartIndicator);
280 int len = TS_PACKET_SIZE - payloadStart;
283 if (pid == 0 && payloadUnitStartIndicator) {
289 parsePAT(&packet[payloadStart], len);
290 }
else if (pid == pmt_pid && packet[payloadStart] == 0x02) {
291 parsePMT(&packet[payloadStart], len);
293 LOGE(
"-> Packet ignored for PID 0x%x", pid);
297 int getPayloadStart(uint8_t *packet,
bool isPES,
298 bool &payloadUnitStartIndicator) {
299 uint8_t adaptionField = (packet[3] & 0x30) >> 4;
300 int adaptationSize = 0;
308 if (adaptionField == 0b11) {
309 adaptationSize = packet[4] + 1;
310 offset += adaptationSize;
314 if (packet[1] & 0x40) {
315 if (!isPES) offset += packet[offset] + 1;
316 payloadUnitStartIndicator =
true;
319 LOGI(
"Payload Unit Start Indicator (PUSI): %d", payloadUnitStartIndicator);
320 LOGI(
"Adaption Field Control: 0x%x / size: %d", adaptionField,
326 void parsePAT(uint8_t *pat,
int len) {
329 int startOfProgramNums = 8;
330 int lengthOfPATValue = 4;
331 int sectionLength = ((pat[1] & 0x0F) << 8) | (pat[2] & 0xFF);
332 LOGI(
"PAT Section Length: %d", sectionLength);
333 if (sectionLength >= len) {
334 LOGE(
"Unexpected PAT Section Length: %d", sectionLength);
338 for (
int i = startOfProgramNums; i <= sectionLength;
339 i += lengthOfPATValue) {
340 int program_number = ((pat[i] & 0xFF) << 8) | (pat[i + 1] & 0xFF);
341 int pid = ((pat[i + 2] & 0x1F) << 8) | (pat[i + 3] & 0xFF);
342 LOGI(
"Program Num: 0x%04X(%d) / PID: 0x%04X(%d) ", program_number,
343 program_number, pid, pid);
345 if (pmt_pid == 0xFFFF && pid >= 0x0020 && pid <= 0x1FFE) {
349 LOGI(
"Using PMT PID: 0x%04X(%d)", pmt_pid, pmt_pid);
352 void parsePMT(uint8_t *pmt,
int len) {
354 assert(pmt[0] == 0x02);
355 int staticLengthOfPMT = 12;
356 int sectionLength = ((pmt[1] & 0x0F) << 8) | (pmt[2] & 0xFF);
357 LOGI(
"- PMT Section Length: %d", sectionLength);
358 int programInfoLength = ((pmt[10] & 0x0F) << 8) | (pmt[11] & 0xFF);
359 LOGI(
"- PMT Program Info Length: %d", programInfoLength);
361 int cursor = staticLengthOfPMT + programInfoLength;
362 while (cursor < sectionLength - 1) {
365 ((pmt[cursor + 1] & 0x1F) << 8) | (pmt[cursor + 2] & 0xFF);
366 LOGI(
"-- Stream Type: 0x%02X(%d) [%s] for Elementary PID: 0x%04X(%d)",
367 (
int)streamType, (
int)streamType,
toStr(streamType), elementaryPID,
371 selected_stream_type = streamType;
376 ((pmt[cursor + 3] & 0x0F) << 8) | (pmt[cursor + 4] & 0xFF);
377 LOGI(
"-- ES Info Length: 0x%04X(%d)", esInfoLength, esInfoLength);
378 cursor += 5 + esInfoLength;
383 LOGI(
"parsePES: %d", pid);
387 bool payloadUnitStartIndicator =
false;
388 int payloadStart = getPayloadStart(packet,
true, payloadUnitStartIndicator);
391 uint8_t *pes = packet + payloadStart;
392 int len = TS_PACKET_SIZE - payloadStart;
394 uint8_t *pesData =
nullptr;
397 if (payloadUnitStartIndicator) {
401 LOGE(
"PES header not aligned correctly");
405 int pesPacketLength =
406 (
static_cast<int>(pes[4]) << 8) |
static_cast<int>(pes[5]);
410 int pesHeaderSize = 6;
411 if ((pes[6] & 0xC0) != 0) {
412 pesHeaderSize += 3 + ((pes[7] & 0xC0) == 0xC0 ? 5 : 0);
413 pesHeaderSize += pes[8];
415 LOGI(
"- PES Header Size: %d", pesHeaderSize);
416 pesData = pes + pesHeaderSize;
417 pesDataSize = len - pesHeaderSize;
419 assert(pesHeaderSize < len);
420 assert(pesDataSize > 0);
423 if (pes_count == 1 && selected_stream_type == MTSStreamType::AUDIO_AAC) {
424 is_adts_missing =
findSyncWord(pesData, pesDataSize) == -1;
427 open_pes_data_size = pesPacketLength;
435 open_pes_data_size -= pesDataSize;
436 if (open_pes_data_size < 0) {
441 LOGI(
"- writing %d bytes (open: %d)", pesDataSize, open_pes_data_size);
443 size_t result = writeData<uint8_t>(p_print, pesData, pesDataSize);
444 assert(result == pesDataSize);
448 writeDataT<uint8_t, AudioDecoder>(p_dec, pesData, pesDataSize);
449 assert(result == pesDataSize);
455 if (pes[0] != 0)
return false;
456 if (pes[1] != 0)
return false;
457 if (pes[2] != 0x1)
return false;
464 case MTSStreamType::AUDIO_MP3:
466 case MTSStreamType::AUDIO_MP3_LOW_BITRATE:
467 return "AUDIO_MP3_LOW_BITRATE";
468 case MTSStreamType::AUDIO_AAC:
470 case MTSStreamType::AUDIO_AAC_LATM:
471 return "AUDIO_AAC_LATM";
478 int findSyncWord(
const uint8_t *buf,
size_t nBytes, uint8_t synch = 0xFF,
479 uint8_t syncl = 0xF0) {
480 for (
int i = 0; i < nBytes - 1; i++) {
481 if ((buf[i + 0] & synch) == synch && (buf[i + 1] & syncl) == syncl)
478 int findSyncWord(
const uint8_t *buf,
size_t nBytes, uint8_t synch = 0xFF, {
…}
488using MPEG_TSDecoder = MTSDecoder;
MTSStreamType
PMT Program Element Stream Types.
Definition CodecMTS.h:20