arduino-audio-tools
CodecMTS.h
1 #pragma once
2 #pragma once
3 
4 #define TS_PACKET_SIZE 188
5 #define TS_HEADER_SIZE 4
6 #define PID_ARRAY_LEN 4
7 
8 #ifndef MTS_UNDERFLOW_LIMIT
9 # define MTS_UNDERFLOW_LIMIT 200
10 #endif
11 
12 #ifndef MTS_WRITE_BUFFER_SIZE
13 # define MTS_WRITE_BUFFER_SIZE 2000
14 #endif
15 
16 #include "AudioTools/AudioCodecs/AudioCodecsBase.h"
17 #include "tsdemux.h"
18 #include "stdlib.h"
19 
20 namespace audio_tools {
21 
26  STREAM_TYPE_VIDEO = 0x01,
27  STREAM_TYPE_VIDEO_H262 = 0x02,
28  STREAM_TYPE_AUDIO_11172 = 0x03,
29  STREAM_TYPE_AUDIO_13818_3 = 0x04,
30  STREAM_TYPE_PRV_SECTIONS = 0x05,
31  STREAM_TYPE_PES_PRV = 0x06,
32  STREAM_TYPE_MHEG = 0x07,
33  STREAM_TYPE_H222_0_DSM_CC = 0x08,
34  STREAM_TYPE_H222_1 = 0x09,
35  STREAM_TYPE_A = 0x0A,
36  STREAM_TYPE_B = 0x0B,
37  STREAM_TYPE_C = 0x0C,
38  STREAM_TYPE_D = 0x0D,
39  STREAM_TYPE_H222_0_AUX = 0x0E,
40  STREAM_TYPE_AUDIO_AAC = 0x0F,
41  STREAM_TYPE_VISUAL = 0x10,
42  STREAM_TYPE_AUDIO_LATM = 0x11,
43  STREAM_TYPE_SL_PES = 0x12,
44  STREAM_TYPE_SL_SECTIONS = 0x13,
45  STREAM_TYPE_SYNC_DOWNLOAD = 0x14,
46  STREAM_TYPE_PES_METADATA = 0x15,
47  STREAM_TYPE_METDATA_SECTIONS = 0x16,
48  STREAM_TYPE_METADATA_DATA_CAROUSEL = 0x17,
49  STREAM_TYPE_METADATA_OBJ_CAROUSEL = 0x18,
50  STREAM_TYPE_METADATA_SYNC_DOWNLOAD = 0x19,
51  STREAM_TYPE_IPMP = 0x1A,
52  STREAM_TYPE_VIDEO_AVC = 0X1B,
53  STREAM_TYPE_VIDEO_H222_0 = 0x1C,
54  STREAM_TYPE_DCII_VIDEO = 0x80,
55  STREAM_TYPE_AUDIO_A53 = 0x81,
56  STREAM_TYPE_SCTE_STD_SUBTITLE = 0x82,
57  STREAM_TYPE_SCTE_ISOCH_DATA = 0x83,
58  STREAM_TYPE_ATSC_PROG_ID = 0x85,
59  STREAM_TYPE_SCTE_25 = 0x86,
60  STREAM_TYPE_AUDIO_EAC3 = 0x87,
61  STREAM_TYPE_AUDIO_DTS_HD = 0x88,
62  STREAM_TYPE_DVB_MPE_FEC = 0x90,
63  STREAM_TYPE_ULE = 0x91,
64  STREAM_TYPE_VEI = 0x92,
65  STREAM_TYPE_ATSC_DATA_SERVICE_TABLE = 0x95,
66  STREAM_TYPE_SCTE_IP_DATA = 0xA0,
67  STREAM_TYPE_DCII_TEXT = 0xC0,
68  STREAM_TYPE_ATSC_SYNC_DATA = 0xC2,
69  STREAM_TYPE_SCTE_AYSNC_DATA = 0xC3,
70  STREAM_TYPE_ATSC_USER_PRIV_PROG_ELEMENTS = 0xC4,
71  STREAM_TYPE_VC1 = 0xEA,
72  STREAM_TYPE_ATSC_USER_PRIV = 0xEB,
73 };
74 
86 class MTSDecoder1 : public AudioDecoder {
87  public:
88  MTSDecoder1() = default;
89 
90  bool begin() override {
91  TRACED();
92 
93  // default supported stream types
94  if (stream_types.empty()){
95  //addStreamType(STREAM_TYPE_PES_METADATA);
96  addStreamType(STREAM_TYPE_AUDIO_AAC);
97  addStreamType(STREAM_TYPE_AUDIO_13818_3);
98  addStreamType(STREAM_TYPE_AUDIO_LATM);
99  }
100 
101  // automatically close when called multiple times
102  if (is_active) {
103  end();
104  }
105 
106  is_active = true;
107  return true;
108  }
109 
110  void end() override {
111  TRACED();
112  is_active = false;
113  }
114 
115  virtual operator bool() override { return is_active; }
116 
117  const char *mime() { return "video/MP2T"; }
118 
119  size_t write(const uint8_t *data, size_t len) override {
120  if (!is_active) return 0;
121  LOGD("MTSDecoder::write: %d", (int)len);
122  size_t result = buffer.writeArray((uint8_t*)data, len);
123  // demux
124  demux(underflowLimit);
125  return result;
126  }
127 
128  void flush(){
129  demux(0);
130  }
131 
133  void resizeBuffer(int size){
134  buffer.resize(size);
135  }
136 
137  void clearStreamTypes(){
138  TRACED();
139  stream_types.clear();
140  }
141 
142  void addStreamType(MTSStreamType type){
143  TRACED();
144  stream_types.push_back(type);
145  }
146 
147  bool isStreamTypeActive(MTSStreamType type){
148  for (int j=0;j<stream_types.size();j++){
149  if (stream_types[j]==type) return true;
150  }
151  return false;
152  }
153 
154  protected:
155  int underflowLimit = MTS_UNDERFLOW_LIMIT;
156  bool is_active = false;
157  SingleBuffer<uint8_t> buffer{MTS_WRITE_BUFFER_SIZE};
158  Vector<uint8_t> data{TS_PACKET_SIZE};
159  Vector<MTSStreamType> stream_types;
160 
161 
162  struct pid_array{
163  int number;
164  int pids[PID_ARRAY_LEN];
165  };
166 
167  uint8_t packetBuff[TS_PACKET_SIZE];
168  bool isSyncByteFound = false;
169  pid_array pidsOfPMT;
170  int16_t relevantPID = -1;
171  int16_t pesDataLength = -1;
172 
173 
174  void demux(int limit){
175  TRACED();
176  TSDCode res = TSD_OK;
177  int count = 0;
178  while (res == TSD_OK && buffer.available() > limit) {
179  parse();
180  count++;
181  }
182  LOGD("Number of demux calls: %d", count);
183  }
184 
185  uint32_t parse() {
186  int len = buffer.available();
187  // If len is too short, return 0
188  if(len < (TS_PACKET_SIZE - TS_HEADER_SIZE)) { return 0; }
189  int read;
190  int aacRead = 0;
191  do {
192  if(!isSyncByteFound) {
193  uint8_t oneByte;
194  do {
195  if(!buffer.readArray(&oneByte, 1)) return 0;
196  } while (oneByte != 0x47);
197  isSyncByteFound = true;
198  packetBuff[0]=0x47;
199  read = buffer.readArray(&packetBuff[1], TS_PACKET_SIZE-1);
200  } else {
201  read = buffer.readArray(packetBuff, TS_PACKET_SIZE);
202  }
203  if(read){
204  int len = parsePacket(packetBuff, &data[aacRead]);
205  if (len<0) {
206  is_active = false;
207  return 0;
208  }
209  aacRead += len;
210  }
211  } while ((len - aacRead) >= (TS_PACKET_SIZE - TS_HEADER_SIZE) && read);
212 
213  return aacRead;
214  }
215 
216  int parsePacket(uint8_t *packet, uint8_t *data){
217  int read = 0;
218 
219  int pid = ((packet[1] & 0x1F) << 8) | (packet[2] & 0xFF);
220  LOGD("PID: 0x%04X(%d)", pid, pid);
221  int payloadUnitStartIndicator = (packet[1] & 0x40) >> 6;
222  LOGD("Payload Unit Start Indicator: %d", payloadUnitStartIndicator);
223  int adaptionFieldControl = (packet[3] & 0x30) >> 4;
224  LOGD("Adaption Field Control: %d", adaptionFieldControl);
225  int remainingAdaptationFieldLength = -1;
226  if ((adaptionFieldControl & 0b10) == 0b10){
227  remainingAdaptationFieldLength = packet[4] & 0xFF;
228  LOGD("Adaptation Field Length: %d", remainingAdaptationFieldLength);
229  }
230  // if we are at the beginning we start with a pat
231  if (payloadUnitStartIndicator){
232  pid = 0;
233  pidsOfPMT.number = 0;
234  }
235 
236  int payloadStart = payloadUnitStartIndicator ? 5 : 4;
237 
238  if (pid == 0){
239  parsePAT(&packet[payloadStart]);
240  } else if (pid == relevantPID){
241  int posOfPacketStart = 4;
242  if (remainingAdaptationFieldLength >= 0) posOfPacketStart = 5 + remainingAdaptationFieldLength;
243  read = parsePES(&packet[posOfPacketStart], posOfPacketStart, payloadUnitStartIndicator ? true : false);
244  } else if (pidsOfPMT.number){
245  for (int i = 0; i < pidsOfPMT.number; i++){
246  if (pid == pidsOfPMT.pids[i]){
247  parsePMT(&packet[payloadStart]);
248  }
249  }
250  }
251 
252  return read;
253  }
254 
255  int parsePAT(uint8_t *pat){
256  int startOfProgramNums = 8;
257  int lengthOfPATValue = 4;
258  int sectionLength = ((pat[1] & 0x0F) << 8) | (pat[2] & 0xFF);
259  LOGD("Section Length: %d", sectionLength);
260  if(sectionLength >= PID_ARRAY_LEN*lengthOfPATValue) {
261  LOGE("Section Length: %d", sectionLength);
262  return 0;
263  }
264  int indexOfPids = 0;
265  for (int i = startOfProgramNums; i <= sectionLength; i += lengthOfPATValue){
266  //int program_number = ((pat[i] & 0xFF) << 8) | (pat[i + 1] & 0xFF);
267  //LOGD("Program Num: 0x%04X(%d)", program_number, program_number);
268  int program_map_PID = ((pat[i + 2] & 0x1F) << 8) | (pat[i + 3] & 0xFF);
269  LOGD("PMT PID: 0x%04X(%d)", program_map_PID, program_map_PID);
270  pidsOfPMT.pids[indexOfPids++] = program_map_PID;
271  }
272  pidsOfPMT.number = indexOfPids;
273  return sectionLength;
274  }
275 
276  int parsePMT(uint8_t *pat){
277  int staticLengthOfPMT = 12;
278  int sectionLength = ((pat[1] & 0x0F) << 8) | (pat[2] & 0xFF);
279  LOGD("Section Length: %d", sectionLength);
280  int programInfoLength = ((pat[10] & 0x0F) << 8) | (pat[11] & 0xFF);
281  LOGD("Program Info Length: %d", programInfoLength);
282 
283  int cursor = staticLengthOfPMT + programInfoLength;
284  while (cursor < sectionLength - 1){
285  int streamType = pat[cursor] & 0xFF;
286  int elementaryPID = ((pat[cursor + 1] & 0x1F) << 8) | (pat[cursor + 2] & 0xFF);
287  LOGD("Stream Type: 0x%02X(%d) Elementary PID: 0x%04X(%d)",
288  streamType, streamType, elementaryPID, elementaryPID);
289 
290  //if (streamType == 0x04) LOGD("The type of this stream is MP3, which is not yet supported in this program.");
291  //if (streamType == 0x0F || streamType == 0x11) relevantPID = elementaryPID;
292  if (isStreamTypeActive((MTSStreamType)streamType)){
293  relevantPID = elementaryPID;
294  }
295 
296  int esInfoLength = ((pat[cursor + 3] & 0x0F) << 8) | (pat[cursor + 4] & 0xFF);
297  LOGD("ES Info Length: 0x%04X(%d)", esInfoLength, esInfoLength);
298  cursor += 5 + esInfoLength;
299  }
300  return sectionLength;
301  }
302 
303  int parsePES(uint8_t *pat, const int posOfPacketStart, const bool isNewPayload){
304  int dataSize = 0;
305  if (isNewPayload){
306  uint8_t streamID = pat[3] & 0xFF;
307  LOGD("Stream ID:%02X ", streamID);
308  const uint8_t posOfPacketLengthLatterHalf = 5;
309  uint16_t pesRemainingPacketLength = ((pat[4] & 0xFF) << 8) | (pat[5] & 0xFF);
310  LOGD("PES Packet length: %d", pesRemainingPacketLength);
311  pesDataLength = pesRemainingPacketLength;
312  const uint8_t posOfHeaderLength = 8;
313  uint8_t pesRemainingHeaderLength = pat[posOfHeaderLength] & 0xFF;
314  LOGD("PES Header length: %d", pesRemainingHeaderLength);
315  int startOfData = posOfHeaderLength + pesRemainingHeaderLength + 1;
316  dataSize = (TS_PACKET_SIZE - posOfPacketStart) - startOfData;
317  if (p_print) p_print->write(&pat[startOfData], dataSize);
318  pesDataLength -= (TS_PACKET_SIZE - posOfPacketStart) - (posOfPacketLengthLatterHalf + 1);
319  } else {
320  dataSize = TS_PACKET_SIZE - posOfPacketStart;
321  if (p_print) p_print->write(pat, dataSize);
322  pesDataLength -= dataSize;
323  }
324  return dataSize;
325  }
326 };
327 
328 } // namespace audio_tools
329 
Docoding of encoded audio into PCM data.
Definition: AudioCodecsBase.h:16
virtual int readArray(T data[], int len)
reads multiple values
Definition: Buffers.h:41
virtual int writeArray(const T data[], int len)
Fills the buffer data.
Definition: Buffers.h:65
MPEG-TS (MTS) decoder. Extracts the AAC audio data from a MPEG-TS (MTS) data stream....
Definition: CodecMTS.h:86
void resizeBuffer(int size)
Set a new write buffer size (default is 2000)
Definition: CodecMTS.h:133
int available() override
provides the number of entries that are available to read
Definition: Buffers.h:219
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition: AudioConfig.h:868
MTSStreamType
Definition: CodecMTS.h:25
Definition: CodecMTS.h:162