111 LOGW(
"MuxerMTS: VideoFormat %d has no standard MPEG-TS stream_type - using private data (0x06)",
125 LOGW(
"MuxerMTS: AudioFormat %d has no standard MPEG-TS stream_type - using private data (0x06)",
139 for (
size_t i = 0; i < len; i++) {
141 for (
int b = 0; b < 8; b++) {
142 crc = (crc & 0x80000000) ? (crc << 1) ^ 0x04C11DB7 : (crc << 1);
241 const char *
mimeVideo()
override {
return "video/mp2t"; }
247 return m !=
nullptr ? m :
"audio/aac";
370 for (; idx < avail; idx++) {
392 if (pkt[1] & 0x80)
return;
393 uint16_t pid = (uint16_t)((pkt[1] & 0x1F) << 8) | pkt[2];
394 bool pusi = (pkt[1] & 0x40) != 0;
395 uint8_t adaptation_control = (pkt[3] >> 4) & 0x03;
396 if (adaptation_control == 0x00)
return;
398 if (adaptation_control == 0x02 || adaptation_control == 0x03) {
403 if (adaptation_control == 0x02)
return;
405 if (payload_len == 0)
return;
406 const uint8_t *payload = pkt + pos;
409 parsePat(payload, payload_len, pusi);
411 parsePmt(payload, payload_len, pusi);
422 if (!pusi || len < 1)
return;
423 size_t off = 1 + (
size_t)data[0];
424 if (off + 8 > len)
return;
425 if (data[off] != 0x00)
return;
426 uint16_t section_length = (uint16_t)((data[off + 1] & 0x0F) << 8) | data[off + 2];
427 size_t after_length = off + 3;
428 size_t section_end = after_length + section_length - 4;
429 if (section_end > len) section_end = len;
430 size_t prog_off = after_length + 5;
431 while (prog_off + 4 <= section_end) {
432 uint16_t program_number = (uint16_t)(data[prog_off] << 8) | data[prog_off + 1];
433 uint16_t pid = (uint16_t)((data[prog_off + 2] & 0x1F) << 8) | data[prog_off + 3];
434 if (program_number != 0) {
445 if (!pusi || len < 1)
return;
446 size_t off = 1 + (
size_t)data[0];
447 if (off + 12 > len)
return;
448 if (data[off] != 0x02)
return;
449 uint16_t section_length = (uint16_t)((data[off + 1] & 0x0F) << 8) | data[off + 2];
450 size_t after_length = off + 3;
451 size_t section_end = after_length + section_length - 4;
452 if (section_end > len) section_end = len;
453 uint16_t program_info_length =
454 (uint16_t)((data[after_length + 7] & 0x0F) << 8) | data[after_length + 8];
455 size_t stream_off = after_length + 9 + program_info_length;
457 uint16_t new_video_pid = 0xFFFF, new_audio_pid = 0xFFFF;
458 uint8_t new_video_type = 0, new_audio_type = 0;
459 while (stream_off + 5 <= section_end) {
460 uint8_t stream_type = data[stream_off];
461 uint16_t es_pid = (uint16_t)((data[stream_off + 1] & 0x1F) << 8) | data[stream_off + 2];
462 uint16_t es_info_length = (uint16_t)((data[stream_off + 3] & 0x0F) << 8) | data[stream_off + 4];
464 new_video_pid = es_pid;
465 new_video_type = stream_type;
467 new_audio_pid = es_pid;
468 new_audio_type = stream_type;
470 stream_off += 5 + es_info_length;
486 if (len < 6 || !(payload[0] == 0 && payload[1] == 0 && payload[2] == 1)) {
487 LOGW(
"DemuxerMTS: missing PES start code on PID %s",
488 isVideo ?
"video" :
"audio");
492 LOGW(
"DemuxerMTS: PES header split across TS packet boundary - dropping unit");
496 size_t header_data_length = (len >= 9) ? payload[8] : 0;
497 size_t header_total = 9 + header_data_length;
499 if (len < header_total) {
500 LOGW(
"DemuxerMTS: PES header split across TS packet boundary - dropping unit");
504 const uint8_t *es = payload + header_total;
505 size_t es_len = len - header_total;
511 if (!frame_open)
return;
530 if (newCap < needed) newCap = needed;
540 if (newCap < needed) newCap = needed;
580 size_t take = old_size < 4 ? 4 - old_size : 0;
581 if (take > len) take = len;
582 for (
size_t i = 0; i < take; i++) {
590 if (b0 == 0xFF && (b1 & 0xF0) == 0xF0) {
591 uint8_t sr_index = (b2 >> 2) & 0x0F;
592 uint8_t chan_cfg = (
uint8_t)(((b2 & 0x01) << 2) | ((b3 >> 6) & 0x03));
593 static const uint32_t rates[16] = {96000, 88200, 64000, 48000, 44100, 32000,
594 24000, 22050, 16000, 12000, 11025, 8000,
604 if (b0 == 0xFF && (b1 & 0xE0) == 0xE0) {
605 uint8_t version = (b1 >> 3) & 0x03;
606 uint8_t sr_index = (b2 >> 2) & 0x03;
607 uint8_t mode = (b3 >> 6) & 0x03;
608 static const uint32_t rates_v1[4] = {44100, 48000, 32000, 0};
609 static const uint32_t rates_v2[4] = {22050, 24000, 16000, 0};
610 static const uint32_t rates_v25[4] = {11025, 12000, 8000, 0};
612 if (version == 0x03) rate = rates_v1[sr_index];
613 else if (version == 0x02) rate = rates_v2[sr_index];
614 else if (version == 0x00) rate = rates_v25[sr_index];
691 const char *
mimeVideo()
override {
return "video/mp2t"; }
718 if (
p_out ==
nullptr) {
719 LOGE(
"output not defined");
754 if (!
is_open || data ==
nullptr || len == 0)
return 0;
776 LOGW(
"MuxerMTS: getVideoInfo().format does not match addJpegFrame()");
780 LOGW(
"MuxerMTS: raw YUV422 is not supported by MPEG-TS");
784 LOGW(
"MuxerMTS: raw RGB565 is not supported by MPEG-TS");
788 LOGW(
"MuxerMTS: raw I420 is not supported by MPEG-TS");
862 b[0] = (
uint8_t)((0x02 << 4) | (((ts >> 30) & 0x07) << 1) | 0x01);
863 uint16_t mid = (uint16_t)((((ts >> 15) & 0x7FFF) << 1) | 0x01);
864 uint16_t low = (uint16_t)(((ts & 0x7FFF) << 1) | 0x01);
878 pcr_base &= 0x1FFFFFFFFULL;
879 buf[0] = (
uint8_t)(pcr_base >> 25);
880 buf[1] = (
uint8_t)(pcr_base >> 17);
881 buf[2] = (
uint8_t)(pcr_base >> 9);
882 buf[3] = (
uint8_t)(pcr_base >> 1);
883 buf[4] = (
uint8_t)(((pcr_base & 0x1) << 7) | 0x7E);
893 const uint8_t *b,
size_t blen) {
895 if (voffset < alen) {
896 size_t take = min(n, alen - voffset);
897 memcpy(dst, a + voffset, take);
901 size_t bOffset = (voffset + written) - alen;
902 memcpy(dst + written, b + bOffset, n - written);
917 const uint8_t *payload,
size_t payload_len,
bool withPcr,
uint64_t pcr) {
918 size_t total_len = header_len + payload_len;
922 size_t remaining = total_len - offset;
923 bool addPcr = first && withPcr;
924 bool use_af = addPcr || remaining < 184;
927 pkt[1] = (
uint8_t)((first ? 0x40 : 0x00) | ((pid >> 8) & 0x1F));
928 pkt[2] = (
uint8_t)(pid & 0xFF);
931 pkt[3] = (
uint8_t)(0x10 | (cc & 0x0F));
935 size_t overhead = 2 + (addPcr ? 6 : 0);
936 chunk = min(remaining, 184 - overhead);
937 size_t stuffing = 184 - overhead - chunk;
938 pkt[3] = (
uint8_t)(0x30 | (cc & 0x0F));
939 pkt[4] = (
uint8_t)(1 + (addPcr ? 6 : 0) + stuffing);
940 pkt[5] = addPcr ? 0x10 : 0x00;
946 for (
size_t i = 0; i < stuffing; i++) pkt[pos++] = 0xFF;
948 copyVirtual(pkt + pos, offset, chunk, header, header_len, payload, payload_len);
950 cc = (
uint8_t)((cc + 1) & 0x0F);
954 }
while (offset < total_len);
962 static const size_t kOptionalLen = 8;
963 size_t pes_payload = kOptionalLen + len;
964 uint16_t pes_len = (pes_payload <= 0xFFFF) ? (uint16_t)pes_payload : 0;
971 hdr[4] = (
uint8_t)(pes_len >> 8);
978 packBytesToTs(pid, cc, hdr,
sizeof(hdr), data, len, withPcr, pts);
982 pkt[pos++] = stream_type;
983 pkt[pos++] = (
uint8_t)(0xE0 | ((pid >> 8) & 0x1F));
984 pkt[pos++] = (
uint8_t)(pid & 0xFF);
993 memset(pkt, 0xFF,
sizeof(pkt));
1002 size_t section_start = pos;
1004 size_t len_pos = pos;
1006 size_t after_len = pos;
1017 size_t section_length = (pos - after_len) + 4;
1018 pkt[len_pos] = (
uint8_t)(0xB0 | ((section_length >> 8) & 0x0F));
1019 pkt[len_pos + 1] = (
uint8_t)(section_length & 0xFF);
1021 pkt[pos++] = (
uint8_t)(crc >> 24);
1022 pkt[pos++] = (
uint8_t)(crc >> 16);
1023 pkt[pos++] = (
uint8_t)(crc >> 8);
1033 memset(pkt, 0xFF,
sizeof(pkt));
1042 size_t section_start = pos;
1044 size_t len_pos = pos;
1046 size_t after_len = pos;
1060 size_t section_length = (pos - after_len) + 4;
1061 pkt[len_pos] = (
uint8_t)(0xB0 | ((section_length >> 8) & 0x0F));
1062 pkt[len_pos + 1] = (
uint8_t)(section_length & 0xFF);
1064 pkt[pos++] = (
uint8_t)(crc >> 24);
1065 pkt[pos++] = (
uint8_t)(crc >> 16);
1066 pkt[pos++] = (
uint8_t)(crc >> 8);
#define LOGW(...)
Definition AudioLoggerIDF.h:29
#define LOGE(...)
Definition AudioLoggerIDF.h:30
virtual size_t write(const uint8_t *data, size_t len)
Definition Arduino.h:120
virtual void flush()
Definition Arduino.h:130
VideoFormat
Video codec/pixel-format identifier, shared by two unrelated uses: the (single) video stream of a con...
Definition VideoOutput.h:29
StreamContentType
Which track write() feeds, for muxers (MuxerAVI, MuxerMP4) that double as a plain,...
Definition Video.h:21
AudioFormat
Audio format codes used by Microsoft e.g. in avi or wav files.
Definition AudioFormat.h:21
const char * toMime(AudioFormat format)
Provides the mime type for a AudioFormat wav code, or nullptr if not known/mapped.
Definition AudioFormat.h:300
@ Audio
Definition Video.h:21
@ Video
Definition Video.h:21