arduino-audio-tools
Loading...
Searching...
No Matches
ContainerMPG.h
Go to the documentation of this file.
1#pragma once
2#include <string.h>
8
9namespace audio_tools {
10
11// packet_start_code / stream_id values used by the ISO/IEC 11172-1 (MPEG-1)
12// Program Stream (also reused, unchanged, by MPEG-2 Program Streams)
13static const uint8_t MPG_PACK_START_CODE = 0xBA;
14static const uint8_t MPG_SYSTEM_HEADER_START_CODE = 0xBB;
15static const uint8_t MPG_PROGRAM_END_CODE = 0xB9;
16static const uint8_t MPG_PROGRAM_STREAM_MAP = 0xBC;
17static const uint8_t MPG_PRIVATE_STREAM_1 = 0xBD;
18static const uint8_t MPG_PADDING_STREAM = 0xBE;
19static const uint8_t MPG_PRIVATE_STREAM_2 = 0xBF;
21static const uint8_t MPG_VIDEO_STREAM_ID = 0xE0;
23static const uint8_t MPG_AUDIO_STREAM_ID = 0xC0;
25static const uint32_t MPG_CLOCK_HZ = 90000;
26
37 public:
38 void resize(size_t size) { vec.resize(size + 4); }
39 size_t writeArray(const uint8_t *data, size_t len) {
40 size_t to_write = min(availableToWrite(), len);
41 memmove(vec.data() + count, data, to_write);
42 count += to_write;
43 return to_write;
44 }
45 void consume(size_t len) {
46 if (len > count) len = count;
47 memmove(vec.data(), vec.data() + len, count - len);
48 count -= len;
49 }
50 uint8_t *data() { return vec.data(); }
51 size_t available() { return count; }
52 size_t availableToWrite() { return vec.size() - count; }
53 void clear() { count = 0; }
54
56 long indexOfStartCode(size_t from = 0) {
57 if (count < 3 || from + 3 > count) return -1;
58 for (size_t i = from; i + 2 < count; i++) {
59 if (vec[i] == 0 && vec[i + 1] == 0 && vec[i + 2] == 1) return (long)i;
60 }
61 return -1;
62 }
63
64 protected:
66 size_t count = 0;
67};
68
111class DemuxerMPG : public Demuxer {
112 public:
115 DemuxerMPG(int bufferSize = 1024) { parse_buffer.resize(bufferSize); }
116
117 const char *mime() override { return "video/mpeg"; }
118
119 bool begin() override {
121 is_parsing_active = true;
122 unit_open = false;
123 is_skip_unit = false;
124 unbounded = false;
125 video_frame_open = false;
126 video_header_parsed = false;
127 audio_header_parsed = false;
130 video_width = 0;
131 video_height = 0;
132 video_fps = 0;
134 audio_channels = 0;
135 total_bytes = 0;
136 return true;
137 }
138
139 void end() override {
140 if (video_frame_open) {
141 if (p_output_video != nullptr) p_output_video->flush();
143 }
144 video_frame_open = false;
145 is_parsing_active = false;
146 }
147
148 operator bool() override { return is_parsing_active; }
149
153 void setOutputAudio(Print &out) override { p_output_audio = &out; }
154
159 void setOutput(Print &out) override { setOutputAudio(out); }
160
163 void setOutputVideo(Print &out) override { p_output_video = &out; }
165
169 void setSendWavHeader(bool flag) override { (void)flag; }
170
175 VideoInfo result;
176 result.width = video_width;
177 result.height = video_height;
178 result.fps = video_fps;
179 result.format = VideoFormat::MPEG1;
180 result.frame_size = 0; // compressed: size varies per frame
182 return result;
183 }
184
188 AudioInfoFormat result;
189 result.sample_rate = audio_sample_rate > 0 ? audio_sample_rate : 44100;
190 result.channels = audio_channels > 0 ? audio_channels : 2;
191 result.bits_per_sample = 16; // nominal - the codec is compressed
192 result.format = AudioFormat::MP3;
193 return result;
194 }
195
196 size_t write(const uint8_t *data, size_t len) override {
197 size_t result = parse_buffer.writeArray(data, len);
198 total_bytes += result;
199 if (is_parsing_active) {
200 while (parse()) {
201 }
202 }
203 return result;
204 }
205
206 protected:
207 bool is_parsing_active = true;
212 uint32_t total_bytes = 0;
213
214 // current streamed unit (PES payload, or a skipped block's payload)
215 bool unit_open = false;
216 bool is_skip_unit = false;
217 bool is_video_unit = false;
218 bool unbounded = false; // PES_packet_length == 0 (video only)
219 size_t remaining = 0;
220
221 // video access-unit framing: a new PES with a PTS starts a new picture
222 bool video_frame_open = false;
223
224 // lazily parsed from the elementary streams themselves
227 uint16_t video_width = 0;
228 uint16_t video_height = 0;
229 float video_fps = 0;
230 uint32_t audio_sample_rate = 0;
231 uint8_t audio_channels = 0;
234 static const size_t VIDEO_PROBE_MAX = 64;
235
239 bool parse() {
240 if (unit_open) return continuePayload();
241
242 if (parse_buffer.available() < 4) return false;
243 uint8_t *buf = parse_buffer.data();
244 if (!(buf[0] == 0 && buf[1] == 0 && buf[2] == 1)) {
245 long idx = parse_buffer.indexOfStartCode();
246 if (idx < 0) {
247 size_t avail = parse_buffer.available();
248 if (avail > 2) parse_buffer.consume(avail - 2);
249 return false;
250 }
251 parse_buffer.consume((size_t)idx);
252 if (parse_buffer.available() < 4) return false;
253 buf = parse_buffer.data();
254 }
255
256 uint8_t id = buf[3];
257 if (id == MPG_PACK_START_CODE) return parsePack();
259 if (id == MPG_PROGRAM_END_CODE) {
261 if (video_frame_open) {
262 if (p_output_video != nullptr) p_output_video->flush();
264 }
265 video_frame_open = false;
266 LOGI("MPEG_program_end_code");
267 return true;
268 }
269 if (id == MPG_PROGRAM_STREAM_MAP || id == MPG_PRIVATE_STREAM_1 ||
271 return parseSkip();
272 if (id >= 0xC0 && id <= 0xDF) return parsePes(id, false);
273 if (id >= 0xE0 && id <= 0xEF) return parsePes(id, true);
274
275 // reserved/unrecognized id: drop this byte and resync on the next
276 // start code
278 return true;
279 }
280
281 bool parsePack() {
282 if (parse_buffer.available() < 12) return false;
284 return true;
285 }
286
288 if (parse_buffer.available() < 6) return false;
289 uint8_t *buf = parse_buffer.data();
290 uint16_t header_length = ((uint16_t)buf[4] << 8) | buf[5];
291 size_t total = 6 + header_length;
292 if (parse_buffer.available() < total) return false;
293 parse_buffer.consume(total);
294 return true;
295 }
296
300 bool parseSkip() {
301 if (parse_buffer.available() < 6) return false;
302 uint8_t *buf = parse_buffer.data();
303 uint16_t len = ((uint16_t)buf[4] << 8) | buf[5];
305 if (len == 0) return true;
306 unit_open = true;
307 is_skip_unit = true;
308 is_video_unit = false;
309 unbounded = false;
310 remaining = len;
311 return continuePayload();
312 }
313
314 bool parsePes(uint8_t id, bool isVideo) {
315 // need the fixed 6-byte PES header plus 1 byte to peek the optional
316 // header's shape
317 if (parse_buffer.available() < 7) return false;
318 uint8_t *buf = parse_buffer.data();
319 uint16_t pes_len = ((uint16_t)buf[4] << 8) | buf[5];
320 uint8_t peek = buf[6];
321
322 size_t optional_len;
323 bool has_pts = false;
324 if (peek == 0x0F) {
325 optional_len = 1;
326 } else if ((peek >> 4) == 0x02) {
327 optional_len = 5;
328 has_pts = true;
329 } else if ((peek >> 4) == 0x03) {
330 optional_len = 10;
331 has_pts = true;
332 } else {
333 LOGW("DemuxerMPG: unsupported PES optional header 0x%02X - treating as no-timestamp",
334 (int)peek);
335 optional_len = 1;
336 }
337 if (parse_buffer.available() < 6 + optional_len) return false;
338
339 uint64_t pts = 0;
340 if (has_pts) pts = readTimestamp(buf + 6);
341 parse_buffer.consume(6 + optional_len);
342 (void)id;
343 (void)pts; // parsed for spec-completeness; not currently exposed
344
345 bool is_unbounded = false;
346 size_t payload_len = 0;
347 if (pes_len == 0) {
348 // PES_packet_length == 0 ("unbounded") is only meaningful for video
349 is_unbounded = isVideo;
350 } else if (pes_len < optional_len) {
351 payload_len = 0; // malformed - be defensive rather than underflow
352 } else {
353 payload_len = (size_t)pes_len - optional_len;
354 }
355
356 if (isVideo && has_pts) {
357 // a PTS marks the first fragment of a new access unit - close out
358 // the previous one
359 if (video_frame_open) {
360 if (p_output_video != nullptr) p_output_video->flush();
362 }
363 video_frame_open = true;
364 }
365
366 unit_open = true;
367 is_skip_unit = false;
368 is_video_unit = isVideo;
369 unbounded = is_unbounded;
370 remaining = payload_len;
371 return continuePayload();
372 }
373
375 if (unbounded) {
376 long idx = parse_buffer.indexOfStartCode();
377 size_t avail = parse_buffer.available();
378 if (idx >= 0) {
379 deliver((size_t)idx);
380 parse_buffer.consume((size_t)idx);
381 unit_open = false;
382 return true;
383 }
384 if (avail > 2) {
385 deliver(avail - 2);
386 parse_buffer.consume(avail - 2);
387 }
388 return false;
389 }
390 size_t avail = parse_buffer.available();
391 size_t to_write = min(avail, remaining);
392 deliver(to_write);
393 parse_buffer.consume(to_write);
394 remaining -= to_write;
395 if (remaining == 0) {
396 unit_open = false;
397 return true;
398 }
399 return false;
400 }
401
402 void deliver(size_t len) {
403 if (len == 0 || is_skip_unit) return;
404 uint8_t *data = parse_buffer.data();
405 if (is_video_unit) {
406 if (!video_header_parsed) probeVideoHeader(data, len);
407 if (p_output_video != nullptr) p_output_video->write(data, len);
408 if (p_output_video_video != nullptr) p_output_video_video->write(data, len);
409 } else {
410 if (!audio_header_parsed) probeAudioHeader(data, len);
411 if (p_output_audio != nullptr) p_output_audio->write(data, len);
412 }
413 }
414
418 static uint64_t readTimestamp(const uint8_t *p) {
419 uint64_t ts = 0;
420 ts |= ((uint64_t)(p[0] >> 1) & 0x07) << 30;
421 ts |= ((uint64_t)((((uint16_t)p[1] << 8) | p[2]) >> 1) & 0x7FFF) << 15;
422 ts |= (uint64_t)((((uint16_t)p[3] << 8) | p[4]) >> 1) & 0x7FFF;
423 return ts;
424 }
425
430 void probeVideoHeader(const uint8_t *data, size_t len) {
431 size_t old_size = (size_t)video_probe.size();
432 size_t take = old_size < VIDEO_PROBE_MAX ? VIDEO_PROBE_MAX - old_size : 0;
433 if (take > len) take = len;
434 for (size_t i = 0; i < take; i++) {
435 uint8_t b = data[i];
437 }
438
439 size_t n = (size_t)video_probe.size();
440 for (size_t i = 0; i + 7 < n; i++) {
441 if (video_probe[i] == 0 && video_probe[i + 1] == 0 &&
442 video_probe[i + 2] == 1 && video_probe[i + 3] == 0xB3) {
443 uint8_t b0 = video_probe[i + 4], b1 = video_probe[i + 5],
444 b2 = video_probe[i + 6], b3 = video_probe[i + 7];
445 video_width = (uint16_t)(((uint16_t)b0 << 4) | (b1 >> 4));
446 video_height = (uint16_t)(((uint16_t)(b1 & 0x0F) << 8) | b2);
447 static const float rates[16] = {0, 23.976f, 24.0f, 25.0f,
448 29.97f, 30.0f, 50.0f, 59.94f,
449 60.0f, 0, 0, 0,
450 0, 0, 0, 0};
451 video_fps = rates[b3 & 0x0F];
452 video_header_parsed = true;
453 break;
454 }
455 }
459 }
460 }
461
464 void probeAudioHeader(const uint8_t *data, size_t len) {
465 size_t old_size = (size_t)audio_probe.size();
466 size_t take = old_size < 4 ? 4 - old_size : 0;
467 if (take > len) take = len;
468 for (size_t i = 0; i < take; i++) {
469 uint8_t b = data[i];
471 }
472 if ((size_t)audio_probe.size() < 4) return;
473
474 uint8_t b0 = audio_probe[0], b1 = audio_probe[1], b2 = audio_probe[2],
475 b3 = audio_probe[3];
476 if (b0 == 0xFF && (b1 & 0xE0) == 0xE0) {
477 uint8_t version = (b1 >> 3) & 0x03; // 11=MPEG1, 10=MPEG2, 00=MPEG2.5
478 uint8_t sr_index = (b2 >> 2) & 0x03;
479 uint8_t mode = (b3 >> 6) & 0x03; // 11=mono
480 static const uint32_t rates_v1[4] = {44100, 48000, 32000, 0};
481 static const uint32_t rates_v2[4] = {22050, 24000, 16000, 0};
482 static const uint32_t rates_v25[4] = {11025, 12000, 8000, 0};
483 uint32_t rate = 0;
484 if (version == 0x03)
485 rate = rates_v1[sr_index];
486 else if (version == 0x02)
487 rate = rates_v2[sr_index];
488 else if (version == 0x00)
489 rate = rates_v25[sr_index];
490 if (rate > 0) {
491 audio_sample_rate = rate;
492 audio_channels = (mode == 0x03) ? 1 : 2;
493 audio_header_parsed = true;
494 }
495 } else {
496 // not a frame sync where we expected one - stop probing so we don't
497 // keep re-checking every write(); getAudioInfo() falls back to
498 // 44100/stereo
499 audio_header_parsed = true;
500 }
503 }
504};
505
567class MuxerMPG : public Muxer {
568 public:
573 MuxerMPG(Print &out) : MuxerMPG() { setOutput(out); }
574
575 const char *mime() override { return "video/mpeg"; }
576
578 void setOutput(Print &out) override { p_out = &out; }
579
583 void setVideoInfo(MuxerVideoConfig config) override { video_cfg = config; }
585
590 void setAudioInfo(AudioInfoFormat info) override {
591 audio_info = info;
594 has_audio = true;
595 }
596 AudioInfoFormat &audioInfo() override { return audio_info; }
597
600 bool begin() override {
601 if (p_out == nullptr) {
602 LOGE("output not defined");
603 return false;
604 }
605 if (video_cfg.width == 0 || video_cfg.height == 0) {
606 LOGE("invalid video size: %d x %d", (int)video_cfg.width,
607 (int)video_cfg.height);
608 return false;
609 }
612 last_scr = 0;
615 is_open = true;
616 return true;
617 }
618
620 void setStreamType(StreamContentType type) override {
621 write_stream_type = type;
622 }
624
626 void end() override {
627 if (is_open && p_out != nullptr) {
628 static const uint8_t end_code[4] = {0x00, 0x00, 0x01,
630 p_out->write(end_code, 4);
631 }
632 is_open = false;
633 }
634
635 operator bool() override { return is_open; }
636
639 size_t write(const uint8_t *data, size_t len) override {
641 return addAudioFrame(data, len);
642 return addVideoFrame(data, len);
643 }
644
651 size_t addVideoFrame(const uint8_t *data, size_t len,
652 bool isKeyFrame = true) override {
653 (void)isKeyFrame;
654 if (!is_open || data == nullptr || len == 0) return 0;
655 size_t written = writeAccessUnit(MPG_VIDEO_STREAM_ID, data, len, videoPts());
657 return written;
658 }
659
663 size_t addJpegFrame(const uint8_t *data, size_t len) override {
664 LOGW("MuxerMPG: MJPEG is not supported by MPEG-1 Program Stream");
665 return addVideoFrame(data, len);
666 }
667 size_t addYUV422Frame(const uint8_t *data, size_t len) override {
668 LOGW("MuxerMPG: raw YUV422 is not supported by MPEG-1 Program Stream");
669 return addVideoFrame(data, len);
670 }
671 size_t addRGB565Frame(const uint8_t *data, size_t len) override {
672 LOGW("MuxerMPG: raw RGB565 is not supported by MPEG-1 Program Stream");
673 return addVideoFrame(data, len);
674 }
675 size_t addI420Frame(const uint8_t *data, size_t len) override {
676 LOGW("MuxerMPG: raw I420 is not supported by MPEG-1 Program Stream");
677 return addVideoFrame(data, len);
678 }
679
683 size_t addAudioFrame(const uint8_t *data, size_t len) override {
684 if (!is_open || !has_audio || data == nullptr || len == 0) return 0;
685 size_t written = writeAccessUnit(MPG_AUDIO_STREAM_ID, data, len, audioPts());
687 return written;
688 }
689
690 uint32_t videoFrameCount() { return video_frame_count; }
691 uint32_t audioFrameCount() { return audio_frame_count; }
692
693 protected:
698 static const size_t MAX_PES_PAYLOAD = 4096;
700 static const uint32_t AUDIO_SAMPLES_PER_FRAME = 1152;
701
702 Print *p_out = nullptr;
705 bool has_audio = false;
706 bool is_open = false;
708 uint32_t video_frame_count = 0;
709 uint32_t audio_frame_count = 0;
710 uint64_t last_scr = 0;
714 static const uint32_t MUX_RATE = 0x3FFFFF;
715
716 uint64_t videoPts() {
717 float fps = video_cfg.fps > 0 ? video_cfg.fps : 25.0f;
718 return (uint64_t)((double)video_frame_count * MPG_CLOCK_HZ / fps);
719 }
720 uint64_t audioPts() {
721 uint32_t sr = audio_info.sample_rate > 0 ? audio_info.sample_rate : 44100;
722 return (uint64_t)((double)audio_frame_count * AUDIO_SAMPLES_PER_FRAME *
723 MPG_CLOCK_HZ / sr);
724 }
725
726 uint64_t clampScr(uint64_t scr) {
727 if (scr < last_scr) scr = last_scr;
728 last_scr = scr;
729 return scr;
730 }
731
732 void writePackHeader(uint64_t scr_in) {
733 uint64_t scr = clampScr(scr_in);
734 static const uint8_t start[4] = {0x00, 0x00, 0x01, MPG_PACK_START_CODE};
735 p_out->write(start, 4);
736 uint8_t b[8];
737 b[0] = (uint8_t)(0x20 | (((scr >> 30) & 0x07) << 1) | 0x01);
738 b[1] = (uint8_t)((scr >> 22) & 0xFF);
739 b[2] = (uint8_t)((((scr >> 15) & 0x7F) << 1) | 0x01);
740 b[3] = (uint8_t)((scr >> 7) & 0xFF);
741 b[4] = (uint8_t)(((scr & 0x7F) << 1) | 0x01);
742 b[5] = (uint8_t)(0x80 | ((MUX_RATE >> 15) & 0x7F));
743 b[6] = (uint8_t)((MUX_RATE >> 7) & 0xFF);
744 b[7] = (uint8_t)(((MUX_RATE & 0x7F) << 1) | 0x01);
745 p_out->write(b, 8);
746 }
747
748 void writeStreamEntry(uint8_t id, bool isVideo) {
749 // P-STD buffer bound: informational only - 46 (x1024 = ~46KB) for
750 // video, 4 (x128 = 512 bytes, ~1 audio frame) for audio
751 uint16_t bound = isVideo ? 46 : 4;
752 uint8_t b[3];
753 b[0] = id;
754 b[1] = (uint8_t)(0xC0 | (isVideo ? 0x20 : 0x00) | ((bound >> 8) & 0x1F));
755 b[2] = (uint8_t)(bound & 0xFF);
756 p_out->write(b, 3);
757 }
758
760 int num_streams = 1 + (has_audio ? 1 : 0);
761 uint16_t header_length = (uint16_t)(6 + 3 * num_streams);
762 static const uint8_t start[4] = {0x00, 0x00, 0x01,
764 p_out->write(start, 4);
765 uint8_t len_b[2] = {(uint8_t)(header_length >> 8),
766 (uint8_t)header_length};
767 p_out->write(len_b, 2);
768
769 uint16_t audio_bound = has_audio ? 1 : 0;
770 uint16_t video_bound = 1;
771 uint8_t b[6];
772 // marker(1) + mux_rate(22) + marker(1)
773 b[0] = (uint8_t)(0x80 | ((MUX_RATE >> 15) & 0x7F));
774 b[1] = (uint8_t)((MUX_RATE >> 7) & 0xFF);
775 b[2] = (uint8_t)(((MUX_RATE & 0x7F) << 1) | 0x01);
776 // audio_bound(6) + fixed_flag(1)=0 + CSPS_flag(1)=0
777 b[3] = (uint8_t)((audio_bound & 0x3F) << 2);
778 // audio_locked(1)=0 + video_locked(1)=0 + marker(1)=1 + video_bound(5)
779 b[4] = (uint8_t)(0x20 | (video_bound & 0x1F));
780 b[5] = 0xFF; // reserved_byte
781 p_out->write(b, 6);
782
785 }
786
787 void writeTimestampField(uint8_t id4, uint64_t ts) {
788 uint8_t b[5];
789 b[0] = (uint8_t)((id4 << 4) | (((ts >> 30) & 0x07) << 1) | 0x01);
790 uint16_t mid = (uint16_t)((((ts >> 15) & 0x7FFF) << 1) | 0x01);
791 uint16_t low = (uint16_t)(((ts & 0x7FFF) << 1) | 0x01);
792 b[1] = (uint8_t)(mid >> 8);
793 b[2] = (uint8_t)mid;
794 b[3] = (uint8_t)(low >> 8);
795 b[4] = (uint8_t)low;
796 p_out->write(b, 5);
797 }
798
800 size_t writeElementaryChunk(uint8_t stream_id, const uint8_t *data,
801 size_t len, bool withPts, uint64_t pts) {
802 writePackHeader(pts);
803 uint16_t optional_len = withPts ? 5 : 1;
804 uint16_t pes_len = (uint16_t)(len + optional_len);
805 uint8_t hdr[6] = {0,
806 0,
807 1,
808 stream_id,
809 (uint8_t)(pes_len >> 8),
810 (uint8_t)pes_len};
811 p_out->write(hdr, 6);
812 if (withPts) {
813 writeTimestampField(0x02, pts);
814 } else {
815 // avoid Print::write(uint8_t): some Print/Stream implementations
816 // (e.g. BaseStream-derived ones) buffer single-byte writes
817 // separately from the write(data, len) path below, which would
818 // reorder this marker byte after the payload - write it as a
819 // one-element array instead so it goes through the same path.
820 static const uint8_t no_ts = 0x0F;
821 p_out->write(&no_ts, 1);
822 }
823 return p_out->write(data, len);
824 }
825
829 size_t writeAccessUnit(uint8_t stream_id, const uint8_t *data, size_t len,
830 uint64_t pts) {
831 size_t offset = 0;
832 size_t written = 0;
833 bool first = true;
834 do {
835 size_t chunk = len - offset;
836 if (chunk > MAX_PES_PAYLOAD) chunk = MAX_PES_PAYLOAD;
837 written +=
838 writeElementaryChunk(stream_id, data + offset, chunk, first, pts);
839 offset += chunk;
840 first = false;
841 } while (offset < len);
842 return written;
843 }
844};
845
846} // namespace audio_tools
WAV Audio Formats used by Microsoft e.g. in AVI video files.
#define LOGW(...)
Definition AudioLoggerIDF.h:29
#define LOGI(...)
Definition AudioLoggerIDF.h:28
#define LOGE(...)
Definition AudioLoggerIDF.h:30
Definition Arduino.h:56
virtual size_t write(const uint8_t *data, size_t len)
Definition Arduino.h:120
virtual void flush()
Definition Arduino.h:130
Common interface for demuxers (DemuxerAVI, DemuxerMP4) that split a container's video and (optional) ...
Definition ContainerCommon.h:164
MPEG-1 System (Program) Stream Demuxer, as defined by ISO/IEC 11172-1: splits the pack_header/system_...
Definition ContainerMPG.h:111
bool is_skip_unit
Definition ContainerMPG.h:216
void setOutput(Print &out) override
Definition ContainerMPG.h:159
MPGParseBuffer parse_buffer
Definition ContainerMPG.h:208
bool audio_header_parsed
Definition ContainerMPG.h:226
bool parse()
Definition ContainerMPG.h:239
void deliver(size_t len)
Definition ContainerMPG.h:402
bool continuePayload()
Definition ContainerMPG.h:374
void setOutputVideo(VideoOutput &out)
Definition ContainerMPG.h:164
Vector< uint8_t > video_probe
Definition ContainerMPG.h:232
bool parsePes(uint8_t id, bool isVideo)
Definition ContainerMPG.h:314
float video_fps
Definition ContainerMPG.h:229
Print * p_output_audio
Definition ContainerMPG.h:209
bool parsePack()
Definition ContainerMPG.h:281
VideoOutput * p_output_video_video
Definition ContainerMPG.h:211
static uint64_t readTimestamp(const uint8_t *p)
Definition ContainerMPG.h:418
VideoInfo getVideoInfo() override
Definition ContainerMPG.h:174
AudioInfoFormat getAudioInfo() override
Definition ContainerMPG.h:187
Print * p_output_video
Definition ContainerMPG.h:210
void setOutputAudio(Print &out) override
Definition ContainerMPG.h:153
bool unbounded
Definition ContainerMPG.h:218
static const size_t VIDEO_PROBE_MAX
Definition ContainerMPG.h:234
bool video_frame_open
Definition ContainerMPG.h:222
void end() override
Definition ContainerMPG.h:139
uint32_t audio_sample_rate
Definition ContainerMPG.h:230
bool is_parsing_active
Definition ContainerMPG.h:207
size_t write(const uint8_t *data, size_t len) override
Definition ContainerMPG.h:196
uint16_t video_width
Definition ContainerMPG.h:227
bool unit_open
Definition ContainerMPG.h:215
bool parseSystemHeader()
Definition ContainerMPG.h:287
void probeVideoHeader(const uint8_t *data, size_t len)
Definition ContainerMPG.h:430
Vector< uint8_t > audio_probe
Definition ContainerMPG.h:233
bool is_video_unit
Definition ContainerMPG.h:217
bool video_header_parsed
Definition ContainerMPG.h:225
const char * mime() override
The container's MIME type (e.g. "video/avi", "video/mp4").
Definition ContainerMPG.h:117
void setSendWavHeader(bool flag) override
Definition ContainerMPG.h:169
bool begin() override
Definition ContainerMPG.h:119
void probeAudioHeader(const uint8_t *data, size_t len)
Definition ContainerMPG.h:464
uint8_t audio_channels
Definition ContainerMPG.h:231
size_t remaining
Definition ContainerMPG.h:219
uint32_t total_bytes
Definition ContainerMPG.h:212
uint16_t video_height
Definition ContainerMPG.h:228
void setOutputVideo(Print &out) override
Definition ContainerMPG.h:163
bool parseSkip()
Definition ContainerMPG.h:300
DemuxerMPG(int bufferSize=1024)
Definition ContainerMPG.h:115
Minimal byte accumulator used by DemuxerMPG to parse start-code delimited units that may straddle wri...
Definition ContainerMPG.h:36
long indexOfStartCode(size_t from=0)
Index of the next 00 00 01 start-code prefix at/after 'from', or -1.
Definition ContainerMPG.h:56
Vector< uint8_t > vec
Definition ContainerMPG.h:65
size_t writeArray(const uint8_t *data, size_t len)
Definition ContainerMPG.h:39
void consume(size_t len)
Definition ContainerMPG.h:45
void resize(size_t size)
Definition ContainerMPG.h:38
size_t count
Definition ContainerMPG.h:66
size_t availableToWrite()
Definition ContainerMPG.h:52
size_t available()
Definition ContainerMPG.h:51
uint8_t * data()
Definition ContainerMPG.h:50
void clear()
Definition ContainerMPG.h:53
Common interface for muxers (MuxerAVI, MuxerMP4) that combine an already-encoded video track (and opt...
Definition ContainerCommon.h:42
MPEG-1 System (Program) Stream Encoder, as defined by ISO/IEC 11172-1: muxes an already-encoded MPEG-...
Definition ContainerMPG.h:567
StreamContentType write_stream_type
Definition ContainerMPG.h:707
bool is_open
Definition ContainerMPG.h:706
void setOutput(Print &out) override
Defines the output: e.g. a local File or a network Client.
Definition ContainerMPG.h:578
void writeStreamEntry(uint8_t id, bool isVideo)
Definition ContainerMPG.h:748
MuxerMPG(Print &out)
Definition ContainerMPG.h:573
size_t addVideoFrame(const uint8_t *data, size_t len, bool isKeyFrame=true) override
Definition ContainerMPG.h:651
AudioInfoFormat audio_info
Definition ContainerMPG.h:704
StreamContentType streamType() override
The track write() currently targets (see setStreamType())
Definition ContainerMPG.h:623
size_t addJpegFrame(const uint8_t *data, size_t len) override
Definition ContainerMPG.h:663
MuxerMPG()
Definition ContainerMPG.h:569
uint32_t audioFrameCount()
Definition ContainerMPG.h:691
static const size_t MAX_PES_PAYLOAD
Definition ContainerMPG.h:698
bool has_audio
Definition ContainerMPG.h:705
static const uint32_t AUDIO_SAMPLES_PER_FRAME
MPEG-1 Layer II/III audio frames are always 1152 samples.
Definition ContainerMPG.h:700
AudioInfoFormat & audioInfo() override
Provides read/write access to the audio track's AudioInfoFormat.
Definition ContainerMPG.h:596
uint64_t audioPts()
Definition ContainerMPG.h:720
void end() override
Writes the MPEG_program_end_code trailer and closes the muxer.
Definition ContainerMPG.h:626
void setVideoInfo(MuxerVideoConfig config) override
Definition ContainerMPG.h:583
void setStreamType(StreamContentType type) override
Selects whether write() feeds the video or the audio track.
Definition ContainerMPG.h:620
size_t addAudioFrame(const uint8_t *data, size_t len) override
Definition ContainerMPG.h:683
size_t write(const uint8_t *data, size_t len) override
Definition ContainerMPG.h:639
uint64_t videoPts()
Definition ContainerMPG.h:716
void setAudioInfo(AudioInfoFormat info) override
Definition ContainerMPG.h:590
uint32_t videoFrameCount()
Definition ContainerMPG.h:690
void writeTimestampField(uint8_t id4, uint64_t ts)
Definition ContainerMPG.h:787
size_t writeAccessUnit(uint8_t stream_id, const uint8_t *data, size_t len, uint64_t pts)
Definition ContainerMPG.h:829
void writeSystemHeader()
Definition ContainerMPG.h:759
size_t addYUV422Frame(const uint8_t *data, size_t len) override
Definition ContainerMPG.h:667
uint32_t audio_frame_count
Definition ContainerMPG.h:709
size_t addI420Frame(const uint8_t *data, size_t len) override
Definition ContainerMPG.h:675
Print * p_out
Definition ContainerMPG.h:702
uint64_t last_scr
Definition ContainerMPG.h:710
size_t addRGB565Frame(const uint8_t *data, size_t len) override
Definition ContainerMPG.h:671
const char * mime() override
Definition ContainerMPG.h:575
size_t writeElementaryChunk(uint8_t stream_id, const uint8_t *data, size_t len, bool withPts, uint64_t pts)
Writes one pack_header + PES header + payload chunk (<= a few KB).
Definition ContainerMPG.h:800
bool begin() override
Definition ContainerMPG.h:600
uint64_t clampScr(uint64_t scr)
Definition ContainerMPG.h:726
uint32_t video_frame_count
Definition ContainerMPG.h:708
MuxerVideoConfig getVideoInfo() override
Provides the video track configuration.
Definition ContainerMPG.h:584
static const uint32_t MUX_RATE
Definition ContainerMPG.h:714
void writePackHeader(uint64_t scr_in)
Definition ContainerMPG.h:732
MuxerVideoConfig video_cfg
Definition ContainerMPG.h:703
Vector implementation which provides the most important methods as defined by std::vector....
Definition Vector.h:21
void shrink_to_fit()
Definition Vector.h:276
void push_back(T &&value)
Definition Vector.h:182
void clear()
Definition Vector.h:176
bool resize(size_t newSize, T value)
Definition Vector.h:266
T * data()
Definition Vector.h:316
int size()
Definition Vector.h:178
Abstract class for video playback. This class is used to assemble a complete video frame in memory....
Definition Video.h:192
virtual size_t write(const uint8_t *data, size_t len)=0
virtual void flush()
Definition Video.h:198
StreamContentType
Which track write() feeds, for muxers (MuxerAVI, MuxerMP4) that double as a plain,...
Definition Video.h:19
@ Audio
Definition Video.h:19
@ Video
Definition Video.h:19
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition LMSEchoCancellationStream.h:6
static const uint8_t MPG_PACK_START_CODE
Definition ContainerMPG.h:13
static const uint8_t MPG_SYSTEM_HEADER_START_CODE
Definition ContainerMPG.h:14
static const uint8_t MPG_VIDEO_STREAM_ID
First (and, in this single-track implementation, only) video stream_id.
Definition ContainerMPG.h:21
static const uint8_t MPG_PROGRAM_END_CODE
Definition ContainerMPG.h:15
static const uint8_t MPG_PROGRAM_STREAM_MAP
Definition ContainerMPG.h:16
static const uint8_t MPG_PRIVATE_STREAM_1
Definition ContainerMPG.h:17
static const uint32_t MPG_CLOCK_HZ
MPEG system clock runs at 90 kHz - the unit PTS/DTS/SCR are expressed in.
Definition ContainerMPG.h:25
static const uint8_t MPG_PADDING_STREAM
Definition ContainerMPG.h:18
static const uint8_t MPG_PRIVATE_STREAM_2
Definition ContainerMPG.h:19
static const uint8_t MPG_AUDIO_STREAM_ID
First (and, in this single-track implementation, only) audio stream_id.
Definition ContainerMPG.h:23
AudioInfo extended with a WAVEFORMATEX-style codec tag (the "wav code"): identifies the codec (PCM,...
Definition AudioFormat.h:389
AudioFormat format
Definition AudioFormat.h:398
sample_rate_t sample_rate
Sample Rate: e.g 44100.
Definition AudioTypes.h:53
uint16_t channels
Number of channels: 2=stereo, 1=mono.
Definition AudioTypes.h:55
uint8_t bits_per_sample
Number of bits per sample (int16_t = 16 bits)
Definition AudioTypes.h:57
Shared video track configuration for muxers (MuxerAVI, MuxerMP4) - call before begin().
Definition ContainerCommon.h:11
float fps
Definition ContainerCommon.h:14
uint16_t height
Definition ContainerCommon.h:13
uint16_t width
Definition ContainerCommon.h:12
VideoFormat format
Definition ContainerCommon.h:15
Basic video information (width/height/codec/frame size), analogous to AudioInfo - common to both Demu...
Definition Video.h:102
uint32_t frame_size
Definition Video.h:115
uint32_t total_file_size
Definition Video.h:121
float fps
Definition Video.h:109
uint16_t height
Frame height in pixels.
Definition Video.h:106
uint16_t width
Frame width in pixels.
Definition Video.h:104
VideoFormat format
Video codec - VideoFormat::UNKNOWN if not (yet) determined.
Definition Video.h:111